فهرست منبع

Merge pull request #21 from jkelleyrtp/jk/portals

Feat: portals
Jonathan Kelley 3 سال پیش
والد
کامیت
7dedad4c26
71فایلهای تغییر یافته به همراه874 افزوده شده و 4698 حذف شده
  1. 5 5
      Cargo.toml
  2. 3 17
      README.md
  3. 54 0
      docs/main-concepts/13-subtrees.md
  4. 0 49
      examples/_examples/anim.rs
  5. 0 57
      examples/_examples/basic.rs
  6. 0 188
      examples/_examples/calculator.rs
  7. 0 181
      examples/_examples/calculator_.rs
  8. 0 37
      examples/_examples/children.rs
  9. 0 65
      examples/_examples/context.rs
  10. 0 75
      examples/_examples/deep.rs
  11. 0 71
      examples/_examples/demo.rs
  12. 0 1
      examples/_examples/demo2.rs
  13. 0 89
      examples/_examples/demoday.rs
  14. 0 46
      examples/_examples/derive.rs
  15. 0 21
      examples/_examples/events.rs
  16. 0 26
      examples/_examples/fragment.rs
  17. 0 33
      examples/_examples/hello.rs
  18. 0 13
      examples/_examples/helloworld.rs
  19. 0 28
      examples/_examples/hifive.rs
  20. 0 59
      examples/_examples/htmlexample.html
  21. 0 59
      examples/_examples/infer.rs
  22. 0 67
      examples/_examples/input.rs
  23. 0 49
      examples/_examples/jackjill.rs
  24. 0 38
      examples/_examples/jackjillrsx.rs
  25. 0 45
      examples/_examples/landingpage.rs
  26. 0 37
      examples/_examples/landingpage2.rs
  27. 0 174
      examples/_examples/list.rs
  28. 0 29
      examples/_examples/listy.rs
  29. 0 23
      examples/_examples/many.rs
  30. 0 193
      examples/_examples/model.rs
  31. 0 13
      examples/_examples/props.rs
  32. 0 20
      examples/_examples/query.rs
  33. 0 86
      examples/_examples/rsxt.rs
  34. 0 126
      examples/_examples/todomvc-nodeps.rs
  35. 0 42
      examples/_examples/todomvc/filtertoggles.rs
  36. 0 39
      examples/_examples/todomvc/main.rs
  37. 0 102
      examples/_examples/todomvc/recoil.rs
  38. 0 43
      examples/_examples/todomvc/state.rs
  39. 0 376
      examples/_examples/todomvc/style.css
  40. 0 29
      examples/_examples/todomvc/todoitem.rs
  41. 0 49
      examples/_examples/todomvc/todolist.rs
  42. 0 167
      examples/_examples/todomvc_simple.rs
  43. 0 200
      examples/_examples/todomvcsingle.rs
  44. 0 47
      examples/_examples/weather.rs
  45. 2 2
      examples/todomvc.rs
  46. 0 1
      packages/core/examples/jsframework.rs
  47. 59 47
      packages/core/src/context.rs
  48. 114 71
      packages/core/src/diff.rs
  49. 8 2
      packages/core/src/diff_stack.rs
  50. 0 1023
      packages/core/src/events.old.rs
  51. 62 93
      packages/core/src/events.rs
  52. 9 7
      packages/core/src/hooklist.rs
  53. 2 2
      packages/core/src/lib.rs
  54. 12 8
      packages/core/src/mutations.rs
  55. 3 3
      packages/core/src/nodes.rs
  56. 2 2
      packages/core/src/resources.rs
  57. 41 14
      packages/core/src/scheduler.rs
  58. 37 1
      packages/core/src/scope.rs
  59. 5 20
      packages/core/src/virtual_dom.rs
  60. 4 7
      packages/core/tests/diffing.rs
  61. 2 2
      packages/core/tests/sharedstate.rs
  62. 1 1
      packages/desktop/src/desktop_context.rs
  63. 36 57
      packages/desktop/src/events.rs
  64. 56 57
      packages/desktop/src/index.js
  65. 3 0
      packages/hooks/src/lib.rs
  66. 177 0
      packages/hooks/src/use_shared_state.rs
  67. 3 3
      packages/hooks/src/usestate.rs
  68. 25 7
      packages/html/src/lib.rs
  69. 1 1
      packages/web/examples/async_web.rs
  70. 147 152
      packages/web/src/dom.rs
  71. 1 1
      packages/web/src/lib.rs

+ 5 - 5
Cargo.toml

@@ -19,7 +19,7 @@ dioxus-mobile = { path = "./packages/mobile", optional = true }
 
 [features]
 # core
-default = ["core", "ssr", "web"]
+default = ["core"]
 core = ["macro", "hooks", "html"]
 macro = ["dioxus-core-macro"]
 hooks = ["dioxus-hooks"]
@@ -55,9 +55,6 @@ env_logger = "0.9.0"
 tokio = { version = "1.12.0", features = ["full"] }
 rand = { version = "0.8.4", features = ["small_rng"] }
 gloo-timers = "0.2.1"
-# surf = { version = "2.3.1", default-features = false, features = [
-#     "wasm-client",
-# ] }
 
 [target.'cfg(target_arch = "wasm32")'.dev-dependencies]
 gloo-timers = "0.2.1"
@@ -66,6 +63,9 @@ console_error_panic_hook = "0.1.6"
 rand = { version = "0.8.4", features = ["small_rng"] }
 wasm-bindgen = { version = "0.2.71", features = ["enable-interning"] }
 
+# surf = { version = "2.3.1", default-features = false, features = [
+#     "wasm-client",
+# ] }
 # surf = { version = "2.2.0", default-features = false, features = [
 #     "wasm-client",
 # ], git = "https://github.com/jkelleyrtp/surf/", branch = "jk/fix-the-wasm" }
@@ -86,7 +86,7 @@ members = [
     "packages/ssr",
     "packages/desktop",
     "packages/mobile",
-    "packages/webview-client"
+    "packages/webview-client",
 ]
 
 

+ 3 - 17
README.md

@@ -89,23 +89,9 @@ If you know React, then you already know Dioxus.
 
 ## Examples:
 
-| File Navigator (Desktop)                                         | Bluetooth scanner (Desktop)                                      | TodoMVC (All platforms)                                          | Widget Gallery                                                   |
-| ---------------------------------------------------------------- | ---------------------------------------------------------------- | ---------------------------------------------------------------- | ---------------------------------------------------------------- |
-| ![asd](https://sixtyfps.io/resources/printerdemo_screenshot.png) | ![asd](https://sixtyfps.io/resources/printerdemo_screenshot.png) | ![asd](https://sixtyfps.io/resources/printerdemo_screenshot.png) | ![asd](https://sixtyfps.io/resources/printerdemo_screenshot.png) |
-
-
-
-| E-Commerce Site                                                  | Doxie Documentation Generator                                    | Chatroom                                                         | Widget Gallery                                                   |
-| ---------------------------------------------------------------- | ---------------------------------------------------------------- | ---------------------------------------------------------------- | ---------------------------------------------------------------- |
-| ![asd](https://sixtyfps.io/resources/printerdemo_screenshot.png) | ![asd](https://sixtyfps.io/resources/printerdemo_screenshot.png) | ![asd](https://sixtyfps.io/resources/printerdemo_screenshot.png) | ![asd](https://sixtyfps.io/resources/printerdemo_screenshot.png) |
-
-
-
-| Printer Demo                                                     | Slide Puzzle                                                     | Todo                                                             | Widget Gallery                                                   |
-| ---------------------------------------------------------------- | ---------------------------------------------------------------- | ---------------------------------------------------------------- | ---------------------------------------------------------------- |
-| ![asd](https://sixtyfps.io/resources/printerdemo_screenshot.png) | ![asd](https://sixtyfps.io/resources/printerdemo_screenshot.png) | ![asd](https://sixtyfps.io/resources/printerdemo_screenshot.png) | ![asd](https://sixtyfps.io/resources/printerdemo_screenshot.png) |
-
-
+| File Navigator (Desktop)                                                                                                                | Bluetooth scanner (Desktop)                                      | TodoMVC (All platforms)                                                                                         | Widget Gallery                                                   |
+| --------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------- |
+| [![asd](https://github.com/DioxusLabs/file-explorer-example/raw/master/image.png)](https://github.com/DioxusLabs/file-explorer-example) | ![asd](https://sixtyfps.io/resources/printerdemo_screenshot.png) | [![asd](https://github.com/DioxusLabs/todomvc/blob/master/example.png)](https://github.com/dioxusLabs/todomvc/) | ![asd](https://sixtyfps.io/resources/printerdemo_screenshot.png) |
 
 
 See the awesome-dioxus page for a curated list of content in the Dioxus Ecosystem.

+ 54 - 0
docs/main-concepts/13-subtrees.md

@@ -0,0 +1,54 @@
+# Subtrees
+
+One way of extending the Dioxus VirtualDom is through the use of "Subtrees." Subtrees are chunks of the VirtualDom tree distinct from the rest of the tree. They still participate in event bubbling, diffing, etc, but will have a separate set of edits generated during the diff phase.
+
+For a VirtualDom that has a root tree with two subtrees, the edits follow a pattern of:
+
+Root
+-> Tree 1
+-> Tree 2 
+-> Original root tree
+
+- Root edits
+- Tree 1 Edits
+- Tree 2 Edits
+- Root Edits
+
+The goal of this functionality is to enable things like Portals, Windows, and inline alternative renderers without needing to spin up a new VirtualDom.
+
+With the right renderer plugins, a subtree could be rendered as anything - a 3D scene, SVG, or even as the contents of a new window or modal. This functionality is similar to "Portals" in React, but much more "renderer agnostic." Portals, by nature, are not necessarily cross-platform and rely on renderer functionality, so it makes sense to abstract their purpose into the subtree concept.
+
+The desktop renderer comes pre-loaded with the window and notification subtree plugins, making it possible to render subtrees into entirely different windows.
+
+Subtrees also solve the "bridging" issues in React where two different renderers need two different VirtualDoms to work properly. In Dioxus, you only ever need one VirtualDom and the right renderer plugins.
+
+
+## API
+
+Due to their importance in the hierarchy, Components - not nodes - are treated as subtree roots.
+
+
+```rust
+
+fn Subtree<P>(cx: Context, props: P) -> DomTree {
+
+}
+
+fn Window() -> DomTree {
+    Subtree {
+        onassign: move |e| {
+            // create window
+        }
+        children() 
+    }
+}
+
+fn 3dRenderer -> DomTree {
+    Subtree {
+        onassign: move |e| {
+            // initialize bevy
+        }
+    }
+}
+
+```

+ 0 - 49
examples/_examples/anim.rs

@@ -1,49 +0,0 @@
-fn main() {
-    // render the
-    let transition = move |cx, (width, height)| {};
-
-    cx.render(rsx! {
-        div {
-            Transition {
-                start: (0, 5),
-                stop: (10, 10),
-                render: transition
-            }
-
-            Transition {
-                start: (0, 5),
-                stop: (10, 10),
-                render: move |cx, (width, height)| {
-                    //
-                    cx.render(rsx!{
-                        div {
-                            style {
-                                width: width,
-                                width: height
-                            }
-                        }
-                    })
-                }
-            }
-        }
-    })
-}
-
-// Animations with signals
-fn signal_based(cx: ()) {
-    const InitPos: (i32, i32) = (0, 0);
-    const EndPos: (i32, i32) = (100, 200);
-
-    let spring = use_spring(cx, move |spring| spring.from(InitPos).to(EndPos));
-
-    cx.render(rsx! {
-        div {
-            style: [
-                width: spring.0,
-                height: spring.1
-            ]
-            button { onclick: move |_| spring.set(InitPos), "Reset" }
-            button { onclick: move |_| spring.set(EndPos), "Animate" }
-        }
-    })
-}

+ 0 - 57
examples/_examples/basic.rs

@@ -1,57 +0,0 @@
-//! Basic example that renders a simple VNode to the browser.
-
-use dioxus::events::on::MouseEvent;
-use dioxus_core as dioxus;
-use dioxus_core::prelude::*;
-use dioxus_html as dioxus_elements;
-use dioxus_web::*;
-
-fn main() {
-    // Setup logging
-    wasm_logger::init(wasm_logger::Config::new(log::Level::Debug));
-    console_error_panic_hook::set_once();
-
-    // Run the app
-    wasm_bindgen_futures::spawn_local(WebsysRenderer::start(App));
-}
-
-static App: FC<()> = |cx, props| {
-    let (state, set_state) = use_state_classic(cx, || 0);
-    cx.render(rsx! {
-        div {
-            section { class: "py-12 px-4 text-center"
-                div { class: "w-full max-w-2xl mx-auto"
-                    span { class: "text-sm font-semibold"
-                        "count: {state}"
-                    }
-                    div {
-                        C1 {
-                            onclick: move |_| set_state(state + 1)
-                            "incr"
-                        }
-                        C1 {
-                            onclick: move |_| set_state(state - 1)
-                            "decr"
-                        }
-                    }
-                }
-            }
-        }
-    })
-};
-
-#[derive(Props)]
-struct IncrementerProps<'a> {
-    onclick: &'a dyn Fn(MouseEvent),
-}
-
-fn C1<'a, 'b>(cx: Context<'a, IncrementerProps<'b>>) -> DomTree<'a> {
-    cx.render(rsx! {
-        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: {cx.onclick}
-            "becr"
-            {cx.children()}
-        }
-    })
-}

+ 0 - 188
examples/_examples/calculator.rs

@@ -1,188 +0,0 @@
-//! Example: Calculator
-//! ------------------
-//!
-//! This example showcases a basic iOS-style calculator app using classic react-style `use_state` hooks. A counterpart of
-//! this example is in `model.rs` which shows the same calculator app implemented using the `model` paradigm. We've found
-//! that the most natural Rust code is more "model-y" than "React-y", but opt to keep this example to show the different
-//! flavors of programming you can use in Dioxus.
-
-use dioxus::events::on::*;
-use dioxus::prelude::*;
-use dioxus_core as dioxus;
-use dioxus_html as dioxus_elements;
-use dioxus_web::WebsysRenderer;
-
-const STYLE: &str = include_str!("../../../examples/assets/calculator.css");
-
-fn main() {
-    wasm_logger::init(wasm_logger::Config::new(log::Level::Debug));
-    console_error_panic_hook::set_once();
-    wasm_bindgen_futures::spawn_local(WebsysRenderer::start(App));
-}
-
-enum Operator {
-    Add,
-    Sub,
-    Mul,
-    Div,
-}
-
-static App: FC<()> = |cx, props| {
-    let (cur_val, set_cur_val) = use_state_classic(cx, || 0.0_f64);
-    let (operator, set_operator) = use_state_classic(cx, || None as Option<Operator>);
-    let (display_value, set_display_value) = use_state_classic(cx, || "0".to_string());
-
-    let clear_display = display_value.eq("0");
-    let clear_text = if clear_display { "C" } else { "AC" };
-
-    let input_digit = move |num: u8| {
-        let mut new = if operator.is_some() {
-            String::new()
-        } else if display_value == "0" {
-            String::new()
-        } else {
-            display_value.clone()
-        };
-        if operator.is_some() {
-            let val = display_value.parse::<f64>().unwrap();
-            set_cur_val(val);
-        }
-
-        new.push_str(num.to_string().as_str());
-        set_display_value(new);
-    };
-
-    let input_dot = move || {
-        let mut new = display_value.clone();
-        new.push_str(".");
-        set_display_value(new);
-    };
-
-    let perform_operation = move || {
-        if let Some(op) = operator.as_ref() {
-            let rhs = display_value.parse::<f64>().unwrap();
-            let new_val = match op {
-                Operator::Add => *cur_val + rhs,
-                Operator::Sub => *cur_val - rhs,
-                Operator::Mul => *cur_val * rhs,
-                Operator::Div => *cur_val / rhs,
-            };
-            set_cur_val(new_val);
-            set_display_value(new_val.to_string());
-            set_operator(None);
-        }
-    };
-
-    let toggle_sign = move |_| {
-        if display_value.starts_with("-") {
-            set_display_value(display_value.trim_start_matches("-").to_string())
-        } else {
-            set_display_value(format!("-{}", *display_value))
-        }
-    };
-    let toggle_percent = move |_| todo!();
-
-    let clear_key = move |_| {
-        set_display_value("0".to_string());
-        if !clear_display {
-            set_operator(None);
-            set_cur_val(0.0);
-        }
-    };
-
-    let keydownhandler = move |evt: KeyboardEvent| match evt.key_code() {
-        KeyCode::Backspace => {
-            let mut new = display_value.clone();
-            if !new.as_str().eq("0") {
-                new.pop();
-            }
-            set_display_value(new);
-        }
-        KeyCode::_0 => input_digit(0),
-        KeyCode::_1 => input_digit(1),
-        KeyCode::_2 => input_digit(2),
-        KeyCode::_3 => input_digit(3),
-        KeyCode::_4 => input_digit(4),
-        KeyCode::_5 => input_digit(5),
-        KeyCode::_6 => input_digit(6),
-        KeyCode::_7 => input_digit(7),
-        KeyCode::_8 => input_digit(8),
-        KeyCode::_9 => input_digit(9),
-        KeyCode::Add => set_operator(Some(Operator::Add)),
-        KeyCode::Subtract => set_operator(Some(Operator::Sub)),
-        KeyCode::Divide => set_operator(Some(Operator::Div)),
-        KeyCode::Multiply => set_operator(Some(Operator::Mul)),
-        _ => {}
-    };
-
-    cx.render(rsx! {
-        div {
-            id: "wrapper"
-            div { class: "app" onkeydown: {keydownhandler}
-                style { "{STYLE}" }
-                div { class: "calculator", 
-                    CalculatorDisplay { val: &display_value}
-                    div { class: "calculator-keypad"
-                        div { class: "input-keys"
-                            div { class: "function-keys"
-                                CalculatorKey { name: "key-clear", onclick: {clear_key} "{clear_text}" }
-                                CalculatorKey { name: "key-sign", onclick: {toggle_sign}, "±"}
-                                CalculatorKey { name: "key-percent", onclick: {toggle_percent} "%"}
-                            }
-                            div { class: "digit-keys"
-                                CalculatorKey { name: "key-0", onclick: move |_| input_digit(0), "0" }
-                                CalculatorKey { name: "key-dot", onclick: move |_|  input_dot(), "●" }
-                                {(1..10).map(move |k| rsx!{
-                                    CalculatorKey { key: "{k}", name: "key-{k}", onclick: move |_| input_digit(k), "{k}" }
-                                })}
-                            }
-                        }
-                        div { class: "operator-keys"
-                            CalculatorKey { name: "key-divide", onclick: move |_| set_operator(Some(Operator::Div)) "÷" }
-                            CalculatorKey { name: "key-multiply", onclick: move |_| set_operator(Some(Operator::Mul)) "×" }
-                            CalculatorKey { name: "key-subtract", onclick: move |_| set_operator(Some(Operator::Sub)) "−" }
-                            CalculatorKey { name: "key-add", onclick: move |_| set_operator(Some(Operator::Add)) "+" }
-                            CalculatorKey { name: "key-equals", onclick: move |_| perform_operation() "=" }
-                        }
-                    }
-                }
-            }
-        }
-    })
-};
-
-#[derive(Props)]
-struct CalculatorKeyProps<'a> {
-    /// Name!
-    name: &'static str,
-
-    /// Click!
-    onclick: &'a dyn Fn(MouseEvent),
-}
-
-fn CalculatorKey<'a, 'r>(cx: Context<'a, CalculatorKeyProps<'r>>) -> DomTree<'a> {
-    cx.render(rsx! {
-        button {
-            class: "calculator-key {cx.name}"
-            onclick: {cx.onclick}
-            {cx.children()}
-        }
-    })
-}
-
-#[derive(Props, PartialEq)]
-struct CalculatorDisplayProps<'a> {
-    val: &'a str,
-}
-
-fn CalculatorDisplay<'a>(cx: Context<'a, CalculatorDisplayProps>) -> DomTree<'a> {
-    use separator::Separatable;
-    // Todo, add float support to the num-format crate
-    let formatted = cx.val.parse::<f64>().unwrap().separated_string();
-    // TODO: make it autoscaling with css
-    cx.render(rsx! {
-        div { class: "calculator-display"
-            div { class: "auto-scaling-text", "{formatted}" }
-        }
-    })
-}

+ 0 - 181
examples/_examples/calculator_.rs

@@ -1,181 +0,0 @@
-use dioxus::events::on::*;
-use dioxus::prelude::*;
-use dioxus_core as dioxus;
-
-const STYLE: &str = include_str!("../../../examples/assets/calculator.css");
-
-fn main() {
-    dioxus_desktop::launch(
-        |builder| {
-            builder
-                .title("Test Dioxus App")
-                .size(340, 560)
-                .resizable(false)
-                .debug(true)
-        },
-        (),
-        App,
-    )
-    .expect("Webview finished");
-}
-
-static App: FC<()> = |cx, props| {
-    let state = use_model(&cx, || Calculator::new());
-
-    let clear_display = state.display_value.eq("0");
-    let clear_text = if clear_display { "C" } else { "AC" };
-    let formatted = state.formatted_display();
-
-    cx.render(rsx! {
-        div { id: "wrapper"
-            div { class: "app", style { "{STYLE}" }
-                div { class: "calculator", onkeypress: move |evt| state.get_mut().handle_keydown(evt),
-                    div { class: "calculator-display", "{formatted}"}
-                    div { class: "calculator-keypad"
-                        div { class: "input-keys"
-                            div { class: "function-keys"
-                                CalculatorKey { name: "key-clear", onclick: move |_| state.get_mut().clear_display(), "{clear_text}" }
-                                CalculatorKey { name: "key-sign", onclick: move |_| state.get_mut().toggle_sign(), "±"}
-                                CalculatorKey { name: "key-percent", onclick: move |_| state.get_mut().toggle_percent(), "%"}
-                            }
-                            div { class: "digit-keys"
-                                CalculatorKey { name: "key-0", onclick: move |_| state.get_mut().input_digit(0), "0" }
-                                CalculatorKey { name: "key-dot", onclick: move |_|  state.get_mut().input_dot(), "●" }
-                                {(1..10).map(move |k| rsx!{
-                                    CalculatorKey { key: "{k}", name: "key-{k}", onclick: move |_|  state.get_mut().input_digit(k), "{k}" }
-                                })}
-                            }
-                        }
-                        div { class: "operator-keys"
-                            CalculatorKey { name:"key-divide", onclick: move |_| state.get_mut().set_operator(Operator::Div), "÷" }
-                            CalculatorKey { name:"key-multiply", onclick: move |_| state.get_mut().set_operator(Operator::Mul), "×" }
-                            CalculatorKey { name:"key-subtract", onclick: move |_| state.get_mut().set_operator(Operator::Sub), "−" }
-                            CalculatorKey { name:"key-add", onclick: move |_| state.get_mut().set_operator(Operator::Add), "+" }
-                            CalculatorKey { name:"key-equals", onclick: move |_| state.get_mut().perform_operation(), "=" }
-                        }
-                    }
-                }
-            }
-        }
-    })
-};
-
-#[derive(Props)]
-struct CalculatorKeyProps<'a> {
-    name: &'static str,
-    onclick: &'a dyn Fn(MouseEvent),
-}
-
-fn CalculatorKey<'a, 'r>(cx: Context<'a, CalculatorKeyProps<'r>>) -> DomTree<'a> {
-    cx.render(rsx! {
-        button {
-            class: "calculator-key {cx.name}"
-            onclick: {cx.onclick}
-            {cx.children()}
-        }
-    })
-}
-
-#[derive(Clone)]
-struct Calculator {
-    display_value: String,
-    operator: Option<Operator>,
-    waiting_for_operand: bool,
-    cur_val: f64,
-}
-#[derive(Clone)]
-enum Operator {
-    Add,
-    Sub,
-    Mul,
-    Div,
-}
-
-impl Calculator {
-    fn new() -> Self {
-        Calculator {
-            display_value: "0".to_string(),
-            operator: None,
-            waiting_for_operand: false,
-            cur_val: 0.0,
-        }
-    }
-    fn formatted_display(&self) -> String {
-        // use separator::Separatable;
-        self.display_value.clone()
-        // .parse::<f64>()
-        // .unwrap()
-        // .separated_string()
-    }
-    fn clear_display(&mut self) {
-        self.display_value = "0".to_string();
-    }
-    fn input_digit(&mut self, digit: u8) {
-        let content = digit.to_string();
-        if self.waiting_for_operand || self.display_value == "0" {
-            self.waiting_for_operand = false;
-            self.display_value = content;
-        } else {
-            self.display_value.push_str(content.as_str());
-        }
-    }
-    fn input_dot(&mut self) {
-        if self.display_value.find(".").is_none() {
-            self.display_value.push_str(".");
-        }
-    }
-    fn perform_operation(&mut self) {
-        if let Some(op) = &self.operator {
-            let rhs = self.display_value.parse::<f64>().unwrap();
-            let new_val = match op {
-                Operator::Add => self.cur_val + rhs,
-                Operator::Sub => self.cur_val - rhs,
-                Operator::Mul => self.cur_val * rhs,
-                Operator::Div => self.cur_val / rhs,
-            };
-            self.cur_val = new_val;
-            self.display_value = new_val.to_string();
-            self.operator = None;
-        }
-    }
-    fn toggle_sign(&mut self) {
-        if self.display_value.starts_with("-") {
-            self.display_value = self.display_value.trim_start_matches("-").to_string();
-        } else {
-            self.display_value = format!("-{}", self.display_value);
-        }
-    }
-    fn toggle_percent(&mut self) {
-        self.display_value = (self.display_value.parse::<f64>().unwrap() / 100.0).to_string();
-    }
-    fn backspace(&mut self) {
-        if !self.display_value.as_str().eq("0") {
-            self.display_value.pop();
-        }
-    }
-    fn set_operator(&mut self, operator: Operator) {
-        self.operator = Some(operator);
-        self.cur_val = self.display_value.parse::<f64>().unwrap();
-        self.waiting_for_operand = true;
-    }
-    fn handle_keydown(&mut self, evt: KeyboardEvent) {
-        match evt.key_code() {
-            KeyCode::Backspace => self.backspace(),
-            KeyCode::_0 => self.input_digit(0),
-            KeyCode::_1 => self.input_digit(1),
-            KeyCode::_2 => self.input_digit(2),
-            KeyCode::_3 => self.input_digit(3),
-            KeyCode::_4 => self.input_digit(4),
-            KeyCode::_5 => self.input_digit(5),
-            KeyCode::_6 => self.input_digit(6),
-            KeyCode::_7 => self.input_digit(7),
-            KeyCode::_8 => self.input_digit(8),
-            KeyCode::_9 => self.input_digit(9),
-            KeyCode::Add => self.operator = Some(Operator::Add),
-            KeyCode::Subtract => self.operator = Some(Operator::Sub),
-            KeyCode::Divide => self.operator = Some(Operator::Div),
-            KeyCode::Multiply => self.operator = Some(Operator::Mul),
-            _ => {}
-        }
-    }
-}

+ 0 - 37
examples/_examples/children.rs

@@ -1,37 +0,0 @@
-//! Basic example that renders a simple VNode to the browser.
-
-use dioxus_core::prelude::*;
-use dioxus_html as dioxus_elements;
-use dioxus_web::*;
-
-fn main() {
-    // Setup logging
-    wasm_logger::init(wasm_logger::Config::new(log::Level::Debug));
-    console_error_panic_hook::set_once();
-
-    // Run the app
-    wasm_bindgen_futures::spawn_local(WebsysRenderer::start(App));
-}
-
-static App: FC<()> = |cx, props| {
-    cx.render(rsx! {
-        Calcier {
-            h2 {"abc 1"}
-            h2 {"abc 2"}
-            h2 {"abc 3"}
-            h2 {"abc 4"}
-            h2 {"abc 5"}
-        }
-    })
-};
-
-static Calcier: FC<()> = |cx, props| {
-    cx.render(rsx! {
-        div {
-            h1 {
-                "abc 0"
-            }
-            {cx.children()}
-        }
-    })
-};

+ 0 - 65
examples/_examples/context.rs

@@ -1,65 +0,0 @@
-//! Example: Context API
-//! --------------------
-//! This example demonstrates how to use the raw context api for sharing state throughout the VirtualDOM Tree.
-//! A custom context must be its own unique type - otherwise use_context will fail. A context may be c
-//!
-//!
-//!
-//!
-//!
-//!
-//!
-//!
-
-use dioxus_core::prelude::*;
-use dioxus_core as dioxus;
-use dioxus_web::WebsysRenderer;
-use dioxus_html as dioxus_elements;
-
-fn main() {
-    wasm_logger::init(wasm_logger::Config::new(log::Level::Trace));
-    console_error_panic_hook::set_once();
-    wasm_bindgen_futures::spawn_local(WebsysRenderer::start(Example));
-}
-
-#[derive(Debug)]
-struct CustomContext([&'static str; 3]);
-
-pub static Example: FC<()> = |cx, props|{
-    cx.use_create_context(|| CustomContext(["Jack", "Jill", "Bob"]));
-
-    cx.render(rsx! {
-        div {
-            class: "py-12 px-4 text-center w-full max-w-2xl mx-auto"
-            span {
-                class: "text-sm font-semibold"
-                "Dioxus Example: Jack and Jill"
-            }
-            h2 {
-                class: "text-5xl mt-2 mb-6 leading-tight font-semibold font-heading"
-                "Hello"
-            }
-
-            CustomButton { id: 0 }
-            CustomButton { id: 1 }
-            CustomButton { id: 2 }
-        }
-    })
-};
-
-#[derive(Props, PartialEq)]
-struct ButtonProps {
-    id: u8,
-}
-
-fn CustomButton(cx: Context<ButtonProps>) -> DomTree {
-    let names = cx.use_context::<CustomContext>();
-    let name = names.0[cx.id as usize];
-
-    cx.render(rsx!{
-        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"
-            "{name}"
-        }
-    })
-}

+ 0 - 75
examples/_examples/deep.rs

@@ -1,75 +0,0 @@
-use std::rc::Rc;
-
-use dioxus::prelude::*;
-use dioxus_core as dioxus;
-use dioxus_html as dioxus_elements;
-
-fn main() {
-    wasm_logger::init(wasm_logger::Config::new(log::Level::Debug));
-    console_error_panic_hook::set_once();
-
-    wasm_bindgen_futures::spawn_local(dioxus_web::WebsysRenderer::start(CustomA))
-}
-
-fn CustomA(cx: Context<()>) -> DomTree {
-    let (val, set_val) = use_state_classic(cx, || "abcdef".to_string() as String);
-
-    cx.render(rsx! {
-        div {
-            class: "m-8"
-            "CustomA {val}"
-            button {
-                "Upper"
-                onclick: move |_| set_val(val.to_ascii_uppercase())
-            }
-            button {
-                "Lower"
-                onclick: move |_| set_val(val.to_ascii_lowercase())
-            }
-            components::CustomB {
-                val: val.clone()
-            }
-        }
-    })
-}
-
-mod components {
-    use std::rc::Rc;
-
-    use super::*;
-
-    #[derive(Debug, Props, PartialEq)]
-    pub struct PropsB {
-        val: String,
-    }
-
-    pub fn CustomB(cx: Context<PropsB>) -> DomTree {
-        let (first, last) = cx.val.split_at(3);
-        cx.render(rsx! {
-            div {
-                class: "m-8"
-                "CustomB {cx.val}"
-                CustomC {
-                    val: first.to_string()
-                }
-                CustomC {
-                    val: last.to_string()
-                }
-            }
-        })
-    }
-
-    #[derive(Debug, Props, PartialEq)]
-    struct PropsC {
-        val: String,
-    }
-
-    fn CustomC(cx: Context<PropsC>) -> DomTree {
-        cx.render(rsx! {
-            div {
-                class: "m-8"
-                "CustomC {cx.val}"
-            }
-        })
-    }
-}

+ 0 - 71
examples/_examples/demo.rs

@@ -1,71 +0,0 @@
-//! An example where the dioxus vdom is running in a native thread, interacting with webview
-//! Content is passed from the native thread into the webview
-use dioxus_core as dioxus;
-use dioxus_core::prelude::*;
-fn main() {
-    dioxus_desktop::launch(
-        |builder| {
-            builder
-                .title("Test Dioxus App")
-                .size(320, 480)
-                .resizable(false)
-                .debug(true)
-        },
-        (),
-        Example,
-    )
-    .expect("Webview finished");
-}
-
-// pub static Example: FC<()> = |cx, props|{
-//     cx.render(html! {
-//         <div>
-//         <svg class="octicon octicon-star v-align-text-bottom"
-//         viewBox="0 0 14 16" version="1.1"
-//         width="14" height="16"
-//         xmlns="http://www.w3.org/2000/svg"
-//         >
-
-//         <path
-//         d="M14 6l-4.9-.64L7 1 4.9 5.36 0 6l3.6 3.26L2.67 14"
-//         xmlns="http://www.w3.org/2000/svg"
-//         >
-//         </path>
-
-//         </svg>
-//         </div>
-//     })
-// };
-pub static Example: FC<()> = |cx, props| {
-    cx.render(rsx! {
-        div  {
-            class: "flex items-center justify-center flex-col"
-            div {
-                class: "flex items-center justify-center"
-                div {
-                    class: "flex flex-col bg-white rounded p-4 w-full max-w-xs"
-                    div { class: "font-bold text-xl", "Example desktop app" }
-                    div { class: "text-sm text-gray-500", "This is running natively" }
-                    div {
-                        class: "flex flex-row items-center justify-center mt-6"
-                        div { class: "font-medium text-6xl", "100%" }
-                    }
-                    div {
-                        class: "flex flex-row justify-between mt-6"
-                        a {
-                            href: "https://www.dioxuslabs.com"
-                            class: "underline"
-                            "Made with dioxus"
-                        }
-                    }
-                    ul {
-                        {(0..10).map(|f| rsx!(li {
-                            key: "{f}"
-                            "{f}"
-                        }))}
-                    }
-                }
-            }
-        }
-    })
-};

+ 0 - 1
examples/_examples/demo2.rs

@@ -1 +0,0 @@
-fn main() {}

+ 0 - 89
examples/_examples/demoday.rs

@@ -1,89 +0,0 @@
-use dioxus_core as dioxus;
-use dioxus_html as dioxus_elements;
-use dioxus_html::*;
-use dioxus_web::{dioxus::prelude::*, WebsysRenderer};
-
-fn main() {
-    wasm_logger::init(wasm_logger::Config::new(log::Level::Debug));
-    console_error_panic_hook::set_once();
-    wasm_bindgen_futures::spawn_local(WebsysRenderer::start(App))
-}
-
-fn App(cx: Context<()>) -> DomTree {
-    cx.render(rsx! {
-        div { class: "dark:bg-gray-800 bg-white relative h-screen"
-            NavBar {}
-            {(0..10).map(|f| rsx!(Landing { key: "{f}" }))}
-        }
-    })
-}
-
-fn NavBar(cx: Context<()>) -> DomTree {
-    cx.render(rsx!{
-        header { class: "h-24 sm:h-32 flex items-center z-30 w-full"
-            div { class: "container mx-auto px-6 flex items-center justify-between"
-                div { class: "uppercase text-gray-800 dark:text-white font-black text-3xl"
-                    svg { focusable:"false" width:"100" height:"100" viewBox: "0 0 512 309"
-                        path { fill: "#000"
-                            d: "M120.81 80.561h96.568v7.676h-87.716v57.767h82.486v7.675h-82.486v63.423h88.722v7.675H120.81V80.561zm105.22 0h10.26l45.467 63.423L328.23 80.56L391.441 0l-103.85 150.65l53.515 74.127h-10.663l-48.686-67.462l-48.888 67.462h-10.461l53.917-74.128l-50.296-70.088zm118.898 7.676V80.56h110.048v7.676h-50.699v136.54h-8.852V88.237h-50.497zM0 80.56h11.065l152.58 228.323l-63.053-84.107L9.254 91.468l-.402 133.31H0V80.56zm454.084 134.224c-1.809 0-3.165-1.4-3.165-3.212c0-1.81 1.356-3.212 3.165-3.212c1.83 0 3.165 1.401 3.165 3.212c0 1.811-1.335 3.212-3.165 3.212zm8.698-8.45h4.737c.064 2.565 1.937 4.29 4.693 4.29c3.079 0 4.823-1.854 4.823-5.325v-21.99h4.823v22.011c0 6.252-3.617 9.853-9.603 9.853c-5.62 0-9.473-3.493-9.473-8.84zm25.384-.28h4.78c.409 2.953 3.294 4.828 7.45 4.828c3.875 0 6.717-2.005 6.717-4.764c0-2.371-1.809-3.794-5.921-4.764l-4.005-.97c-5.62-1.316-8.181-4.032-8.181-8.602c0-5.54 4.521-9.227 11.303-9.227c6.308 0 10.916 3.686 11.196 8.925h-4.694c-.452-2.867-2.95-4.657-6.567-4.657c-3.81 0-6.35 1.833-6.35 4.635c0 2.22 1.635 3.493 5.683 4.441l3.423.841c6.373 1.488 9 4.075 9 8.753c0 5.95-4.607 9.68-11.97 9.68c-6.89 0-11.52-3.558-11.864-9.12z" 
-                        }
-                    }
-                }
-                div { class:"flex items-center"
-                    nav { class: "font-sen text-gray-800 dark:text-white uppercase text-lg lg:flex items-center hidden"
-                        a { href: "#", class:"py-2 px-6 flex text-indigo-500 border-b-2 border-indigo-500"
-                            "Home"
-                        }
-                        a { href: "#", class: "py-2 px-6 flex hover:text-indigo-500"
-                            "Watch"
-                        }
-                        a { href: "#", class: "py-2 px-6 flex hover:text-indigo-500"
-                            "Product"
-                        }
-                        a { href: "#", class: "py-2 px-6 flex hover:text-indigo-500"
-                            "Contact"
-                        }
-                        a { href: "#", class: "py-2 px-6 flex hover:text-indigo-500"
-                            "Career"
-                        }
-                    }
-                    button { class: "lg:hidden flex flex-col ml-4"
-                        span { class: "w-6 h-1 bg-gray-800 dark:bg-white mb-1" }
-                        span { class: "w-6 h-1 bg-gray-800 dark:bg-white mb-1" }
-                        span { class: "w-6 h-1 bg-gray-800 dark:bg-white mb-1" }
-                    }
-                }
-            }
-        }
-    })
-}
-
-fn Landing(cx: Context<()>) -> DomTree {
-    cx.render(rsx!{
-        div { class: "bg-white dark:bg-gray-800 flex relative z-20 items-center"
-            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 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
-                        hybrid static &amp; server rendering, TypeScript support, smart bundling, route pre-fetching, and \n
-                        more. No config needed."
-                    }
-                    div { class: "flex items-center justify-center mt-4"
-                        a { href: "#" class: "uppercase py-2 px-4 bg-gray-800 border-2 border-transparent text-white text-md mr-4 hover:bg-gray-900"
-                            "Get started"
-                        }
-                        a{ href: "#" class: "uppercase py-2 px-4 bg-transparent border-2 border-gray-800 text-gray-800 dark:text-white hover:bg-gray-800 hover:text-white text-md"
-                            "Documentation"
-                        }
-                    }
-                }
-                div { class: "block w-full mx-auto mt-6 md:mt-0 relative"
-                    img { src: "/images/object/12.svg" class: "max-w-xs md:max-w-2xl m-auto" }
-                }
-            }
-        }
-    })
-}

+ 0 - 46
examples/_examples/derive.rs

@@ -1,46 +0,0 @@
-use dioxus::{events::on::MouseEvent, prelude::*};
-use dioxus_core as dioxus;
-use dioxus_html as dioxus_elements;
-use dioxus_web::WebsysRenderer;
-
-fn main() {
-    wasm_logger::init(wasm_logger::Config::new(log::Level::Debug));
-    console_error_panic_hook::set_once();
-    wasm_bindgen_futures::spawn_local(WebsysRenderer::start(App));
-}
-
-fn App(cx: Context<()>) -> DomTree {
-    let cansee = use_state(cx, || false);
-    rsx! { in cx,
-        div {
-            "Shadow of the child:"
-            button { onclick: move |_| cansee.set(!**cansee)
-                "Gaze into the void"
-            }
-            {cansee.then(|| rsx!{ Child {} })}
-        }
-    }
-}
-
-fn Child(cx: Context<()>) -> DomTree {
-    rsx! { in cx,
-        section { class: "py-6 bg-coolGray-100 text-coolGray-900"
-            div { class: "container mx-auto flex flex-col items-center justify-center p-4 space-y-8 md:p-10 md:px-24 xl:px-48"
-                h1 { class: "text-5xl font-bold leading-none text-center",
-                    "Sign up now"
-                }
-                p { class: "text-xl font-medium text-center",
-                    "At a assumenda quas cum earum ut itaque commodi saepe rem aspernatur quam natus quis nihil quod, hic explicabo doloribus magnam neque, exercitationem eius sunt!"
-                }
-                div { class: "flex flex-col space-y-4 sm:space-y-0 sm:flex-row sm:space-x-8"
-                    button { class: "px-8 py-3 text-lg font-semibold rounded bg-violet-600 text-coolGray-50",
-                        "Get started"
-                    }
-                    button { class: "px-8 py-3 text-lg font-normal border rounded bg-coolGray-800 text-coolGray-50 border-coolGray-700",
-                        "Learn more"
-                    }
-                }
-            }
-        }
-    }
-}

+ 0 - 21
examples/_examples/events.rs

@@ -1,21 +0,0 @@
-use dioxus_core as dioxus;
-use dioxus_core::events::on::*;
-use dioxus_core::prelude::*;
-
-fn main() {}
-
-fn autocomplete() {
-    // let handler = move |evt| {
-    //     let r = evt.alt_key();
-    //     if evt.alt_key() {}
-    // };
-
-    // let g = rsx! {
-    //     button {
-    //         button {
-    //             onclick: {handler}
-    //         }
-    //     }
-
-    // };
-}

+ 0 - 26
examples/_examples/fragment.rs

@@ -1,26 +0,0 @@
-//! Basic example that renders a simple VNode to the browser.
-
-use dioxus_core::prelude::*;
-use dioxus_html as dioxus_elements;
-use dioxus_web::*;
-
-fn main() {
-    // Setup logging
-    wasm_logger::init(wasm_logger::Config::new(log::Level::Debug));
-    console_error_panic_hook::set_once();
-
-    // Run the app
-    wasm_bindgen_futures::spawn_local(WebsysRenderer::start(App));
-}
-
-static App: FC<()> = |cx, props| {
-    cx.render(rsx! {
-        h2 { "abc 1" }
-        div {
-            "hello world!"
-        }
-        Fragment {
-            h2 { "abc 2"}
-        }
-    })
-};

+ 0 - 33
examples/_examples/hello.rs

@@ -1,33 +0,0 @@
-use dioxus_core as dioxus;
-use dioxus_core::prelude::*;
-use dioxus_html as dioxus_elements;
-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");
-    dioxus_web::intern_cache();
-
-    wasm_bindgen_futures::spawn_local(WebsysRenderer::start(Example));
-}
-
-pub static Example: FC<()> = |cx, props| {
-    let nodes = (0..500).map(|f| rsx! (li {"div"}));
-    cx.render(rsx! {
-        div {
-            span {
-                class: "px-2 py-1 flex w-36 mt-4 items-center text-xs rounded-md font-semibold text-yellow-500 bg-yellow-100"
-                "DUE DATE : 189 JUN"
-            }
-            p {
-                "these"
-                "are"
-                "text"
-                "nodes"
-            }
-            {nodes}
-        }
-    })
-};

+ 0 - 13
examples/_examples/helloworld.rs

@@ -1,13 +0,0 @@
-use dioxus_core as dioxus;
-use dioxus_html as dioxus_elements;
-use dioxus_web::prelude::*;
-
-fn main() {
-    wasm_bindgen_futures::spawn_local(dioxus_web::WebsysRenderer::start(App))
-}
-
-fn App(cx: Context<()>) -> DomTree {
-    cx.render(rsx! {
-        div { "Hello, world!" }
-    })
-}

+ 0 - 28
examples/_examples/hifive.rs

@@ -1,28 +0,0 @@
-//! An example where the dioxus vdom is running in a native thread, interacting with webview
-//! Content is passed from the native thread into the webview
-use dioxus_core as dioxus;
-use dioxus_core::prelude::*;
-fn main() {
-    dioxus_desktop::launch(
-        |builder| {
-            builder
-                .title("Test Dioxus App")
-                .size(320, 480)
-                .resizable(false)
-                .debug(true)
-        },
-        (),
-        App,
-    )
-    .expect("Webview finished");
-}
-
-static App: FC<()> = |cx, props| {
-    let hifives = use_model(&cx, || 0);
-    cx.render(rsx! {
-        div {
-            h1 { "Hi-fives collected: {hifives}" }
-            button { "Hi five me!", onclick: move |_| *hifives.get_mut() += 1 }
-        }
-    })
-};

+ 0 - 59
examples/_examples/htmlexample.html

@@ -1,59 +0,0 @@
-<div class="shadow-lg rounded-2xl p-4 bg-white dark:bg-gray-700 w-full">
-    <p class="font-bold text-md text-black dark:text-white">
-        "Messages"
-    </p>
-    <ul>
-        <li class="flex items-center my-6 space-x-2">
-            <a href="#" class="block relative">
-                <img alt="profil" src="/images/person/1.jpg" class="mx-auto object-cover rounded-full h-10 w-10 " />
-            </a>
-            <div class="flex flex-col">
-                <span class="text-sm text-gray-900 font-semibold dark:text-white ml-2">
-                    {title}
-                </span>
-                <span class="text-sm text-gray-400 dark:text-gray-300 ml-2">
-                    "Hey John ! Do you read the NextJS doc ?"
-                </span>
-            </div>
-        </li>
-        <li class="flex items-center my-6 space-x-2">
-            <a href="#" class="block relative">
-                <img alt="profil" src="/images/person/5.jpg" class="mx-auto object-cover rounded-full h-10 w-10 " />
-            </a>
-            <div class="flex flex-col">
-                <span class="text-sm text-gray-900 font-semibold dark:text-white ml-2">
-                    "Marie Lou"
-                </span>
-                <span class="text-sm text-gray-400 dark:text-gray-300 ml-2">
-                    "No I think the dog is better..."
-                </span>
-            </div>
-        </li>
-        <li class="flex items-center my-6 space-x-2">
-            <a href="#" class="block relative">
-                <img alt="profil" src="/images/person/6.jpg" class="mx-auto object-cover rounded-full h-10 w-10 " />
-            </a>
-            <div class="flex flex-col">
-                <span class="text-sm text-gray-900 font-semibold dark:text-white ml-2">
-                    "Ivan Buck"
-                </span>
-                <span class="text-sm text-gray-400 dark:text-gray-300 ml-2">
-                    "Seriously ? haha Bob is not a children !"
-                </span>
-            </div>
-        </li>
-        <li class="flex items-center my-6 space-x-2">
-            <a href="#" class="block relative">
-                <img alt="profil" src="/images/person/7.jpg" class="mx-auto object-cover rounded-full h-10 w-10 " />
-            </a>
-            <div class="flex flex-col">
-                <span class="text-sm text-gray-900 font-semibold dark:text-white ml-2">
-                    "Marina Farga"
-                </span>
-                <span class="text-sm text-gray-400 dark:text-gray-300 ml-2">
-                    "Do you need that deisgn ?"
-                </span>
-            </div>
-        </li>
-    </ul>
-</div>

+ 0 - 59
examples/_examples/infer.rs

@@ -1,59 +0,0 @@
-use dioxus_core as dioxus;
-use dioxus_core::{events::on::MouseEvent, prelude::*};
-use dioxus_web::WebsysRenderer;
-use dioxus_html as dioxus_elements;
-
-
-fn main() {
-    // Setup logging
-    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(Example));
-}
-
-// this is a component
-pub static Example: FC<()> = |cx, props|{
-    let (event, set_event) = use_state_classic(cx, || None);
-
-    let handler = move |evt| {
-        set_event(Some(evt));
-    };
-
-    log::info!("hello world");
-
-    cx.render(rsx! {
-        div {  
-            
-            class: "py-12 px-4 w-full max-w-2xl mx-auto bg-red-100"
-            span { 
-                class: "text-sm font-semibold"
-                "Dioxus Example: Synthetic Events"
-            }            
-            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"
-                "press me"
-            }
-            pre {
-                onmousemove: {handler}
-                id: "json"
-                "Hello world"
-            }
-            Example2 { name: "Blah".into() }
-        }
-    })
-};
-
-#[derive(Debug, PartialEq, Props)]
-struct ExampleProps {
-    name: String,
-}
-
-pub static Example2: FC<ExampleProps> = |cx, props|{
-    cx.render(rsx! {
-        div {
-            h1 {"hello {cx.name}"}
-        }
-    })
-};

+ 0 - 67
examples/_examples/input.rs

@@ -1,67 +0,0 @@
-use dioxus_core as dioxus;
-use dioxus_core::prelude::*;
-use dioxus_web::WebsysRenderer;
-use dioxus_html as dioxus_elements;
-
-
-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(App));
-}
-
-static App: FC<()> = |cx, props|{
-    let (val, set_val) = use_state_classic(cx, || "asd".to_string());
-
-    cx.render(rsx! {
-        div { class: "max-w-lg max-w-xs bg-blue-800 shadow-2xl rounded-lg mx-auto text-center py-12 mt-4 rounded-xl"
-            div { class: "container py-5 max-w-md mx-auto"
-                h1 { class: "text-gray-200 text-center font-extrabold -mt-3 text-3xl", 
-                    "Text Input Example"
-                } 
-                div { class: "mb-4"
-                    input {
-                        placeholder: "Username"
-                        class: "shadow appearance-none rounded w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline"
-                        id: "username" 
-                        r#type: "text"
-                        value: "{val}"
-                        oninput: move |evet| set_val(evet.value())
-                    }
-                    p { "Val is: {val}" }
-                }            
-            }
-        }
-    })
-};
-
-pub static Example: FC<()> = |cx, props|{
-    cx.render(rsx! {
-        div { class: "max-w-lg max-w-xs bg-blue-800 shadow-2xl rounded-lg mx-auto text-center py-12 mt-4 rounded-xl"
-            div { class: "container py-5 max-w-md mx-auto"
-                h1 { class: "text-gray-200 text-center font-extrabold -mt-3 text-3xl",
-                    "Text Input Example"
-                }
-                UserInput {}
-            }
-        }
-    })
-};
-
-static UserInput: FC<()> = |cx, props|{
-    let (val, set_val) = use_state_classic(cx, || "asd".to_string());
-
-    rsx! { in cx,
-        div { class: "mb-4"
-            input { class: "shadow appearance-none rounded w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline"
-                placeholder: "Username"
-                id: "username"
-                r#type: "text"
-                oninput: move |evet| set_val(evet.value())
-            }
-            p { "Val is: {val}" }
-        }
-    }
-};

+ 0 - 49
examples/_examples/jackjill.rs

@@ -1,49 +0,0 @@
-use dioxus::prelude::*;
-use dioxus_core as dioxus;
-use dioxus_web::WebsysRenderer;
-
-fn main() {
-    wasm_logger::init(wasm_logger::Config::new(log::Level::Debug));
-    console_error_panic_hook::set_once();
-
-    wasm_bindgen_futures::spawn_local(WebsysRenderer::start(Example))
-}
-
-pub static Example: FC<()> = |cx, props| {
-    let (name, set_name) = use_state_classic(cx, || "...?");
-
-    log::debug!("Running component....");
-
-    cx.render(html! {
-        <div>
-            <section class="py-12 px-4 text-center">
-                <div class="w-full max-w-2xl mx-auto">
-                    // Tagline
-                    <span class="text-sm font-semibold">
-                        "Dioxus Example: Jack and Jill"
-                    </span>
-
-                    // Header
-                    <h2 class="text-5xl mt-2 mb-6 leading-tight font-semibold font-heading">
-                        "Hello, {name}"
-                    </h2>
-
-                    // Control buttons
-                    <div>
-                        <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!"
-                        </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")}>
-                            "Jill!"
-                        </button>
-                    </div>
-                </div>
-            </section>
-        </div>
-    })
-};

+ 0 - 38
examples/_examples/jackjillrsx.rs

@@ -1,38 +0,0 @@
-use dioxus::prelude::*;
-use dioxus_core as dioxus;
-use dioxus_html as dioxus_elements;
-use dioxus_web::WebsysRenderer;
-
-fn main() {
-    wasm_logger::init(wasm_logger::Config::new(log::Level::Debug));
-    console_error_panic_hook::set_once();
-    wasm_bindgen_futures::spawn_local(WebsysRenderer::start(Example))
-}
-
-pub static Example: FC<()> = |cx, props| {
-    let (name, set_name) = use_state_classic(cx, || "...?");
-    cx.render(rsx! {
-        section { class: "py-12 px-4 text-center"
-            div { class: "w-full max-w-2xl mx-auto"
-                span { class: "text-sm font-semibold"
-                    "Dioxus Example: Jack and Jill"
-                }
-                h2 { class: "text-5xl mt-2 mb-6 leading-tight font-semibold font-heading"
-                    "Hello, {name}"
-                }
-                div {
-                    button {
-                        class:"inline-block py-4 px-8 m-2 leading-none text-white bg-indigo-600 hover:bg-indigo-900 font-semibold rounded shadow"
-                        onclick: move |_| set_name("jack")
-                        "Jack!"
-                    }
-                    button {
-                        class:"inline-block py-4 px-8 m-2 leading-none text-white bg-indigo-600 hover:bg-indigo-900 font-semibold rounded shadow"
-                        onclick: move |_| set_name("jill")
-                        "Jill!"
-                    }
-                }
-            }
-        }
-    })
-};

+ 0 - 45
examples/_examples/landingpage.rs

@@ -1,45 +0,0 @@
-//! Basic example that renders a simple VNode to the browser.
-
-use std::rc::Rc;
-
-use dioxus_core::prelude::*;
-use dioxus_html as dioxus_elements;
-use dioxus_web::*;
-
-fn main() {
-    // Setup logging
-    // wasm_logger::init(wasm_logger::Config::new(log::Level::Debug));
-    console_error_panic_hook::set_once();
-    // Run the app
-    wasm_bindgen_futures::spawn_local(WebsysRenderer::start(App));
-}
-
-static App: FC<()> = |cx, props| {
-    let (contents, set_contents) = use_state_classic(cx, || "asd");
-
-    cx.render(rsx! {
-        div  {
-            class: "flex items-center justify-center flex-col"
-            div {
-                class: "flex items-center justify-center"
-                div {
-                    class: "flex flex-col bg-white rounded p-4 w-full max-w-xs"
-                    div { class: "font-bold text-xl", "Example cloud app" }
-                    div { class: "text-sm text-gray-500", "This is running in the cloud!!" }
-                    div {
-                        class: "flex flex-row items-center justify-center mt-6"
-                        div { class: "font-medium text-6xl", "100%" }
-                    }
-                    div {
-                        class: "flex flex-row justify-between mt-6"
-                        a {
-                            href: "https://www.dioxuslabs.com"
-                            class: "underline"
-                            "Made with dioxus"
-                        }
-                    }
-                }
-            }
-        }
-    })
-};

+ 0 - 37
examples/_examples/landingpage2.rs

@@ -1,37 +0,0 @@
-//! Basic example that renders a simple VNode to the browser.
-
-use dioxus_core::prelude::*;
-use dioxus_html as dioxus_elements;
-use dioxus_web::*;
-
-fn main() {
-    // Setup logging and panic handling
-    wasm_logger::init(wasm_logger::Config::new(log::Level::Debug));
-    console_error_panic_hook::set_once();
-
-    // Run the app
-    wasm_bindgen_futures::spawn_local(WebsysRenderer::start(App));
-}
-
-static App: FC<()> = |cx, props| {
-    let (contents, set_contents) = use_state_classic(cx, || "asd");
-
-    cx.render(rsx! {
-        div  { class: "flex items-center justify-center flex-col"
-            div { class: "flex items-center justify-center"
-                div { class: "flex flex-col bg-white rounded p-4 w-full max-w-xs"
-                    div { class: "font-bold text-xl", "Example Web app" }
-                    div { class: "text-sm text-gray-500", "This is running in your browser!" }
-                    div { class: "flex flex-row items-center justify-center mt-6"
-                        div { class: "font-medium text-6xl", "100%" }
-                    }
-                    div { class: "flex flex-row justify-between mt-6"
-                        a { href: "https://www.dioxuslabs.com", class: "underline"
-                            "Made with dioxus"
-                        }
-                    }
-                }
-            }
-        }
-    })
-};

+ 0 - 174
examples/_examples/list.rs

@@ -1,174 +0,0 @@
-use dioxus_core as dioxus;
-use dioxus_core::prelude::*;
-use dioxus_html as dioxus_elements;
-use dioxus_web::WebsysRenderer;
-use std::collections::BTreeMap;
-
-fn main() {
-    wasm_logger::init(wasm_logger::Config::new(log::Level::Debug));
-    console_error_panic_hook::set_once();
-    wasm_bindgen_futures::spawn_local(WebsysRenderer::start(App));
-}
-
-static APP_STYLE: &'static str = include_str!("./todomvc/style.css");
-
-#[derive(PartialEq, Clone, Copy)]
-pub enum FilterState {
-    All,
-    Active,
-    Completed,
-}
-
-#[derive(Debug, PartialEq, Clone)]
-pub struct TodoItem {
-    pub id: uuid::Uuid,
-    pub checked: bool,
-    pub contents: String,
-}
-
-static App: FC<()> = |cx, props| {
-    let (draft, set_draft) = use_state_classic(cx, || "".to_string());
-    let (filter, set_filter) = use_state_classic(cx, || FilterState::All);
-    let todos = use_state(cx, || BTreeMap::<uuid::Uuid, TodoItem>::new());
-    cx.render(rsx!(
-        div {
-            id: "app"
-            div {
-                header {
-                    class: "header"
-                    h1 {"todos"}
-                    button {
-                        "press me"
-                        onclick: move |evt| {
-                            let contents = draft.clone();
-                            todos.modify(|f| {
-                                let id = uuid::Uuid::new_v4();
-                                f.insert(id.clone(), TodoItem {
-                                    id,
-                                    checked: false,
-                                    contents
-                                });
-                            })
-                        }
-                    }
-                    input {
-                        class: "new-todo"
-                        placeholder: "What needs to be done?"
-                        oninput: move |evt| set_draft(evt.value())
-                    }
-                }
-
-                { // list
-                    todos
-                    .iter()
-                    .filter(|(id, item)| match filter {
-                        FilterState::All => true,
-                        FilterState::Active => !item.checked,
-                        FilterState::Completed => item.checked,
-                    })
-                    .map(|(id, todo)| {
-                        rsx!{
-                            li {
-                                key: "{id}"
-                                "{todo.contents}"
-                                input {
-                                    class: "toggle"
-                                    r#type: "checkbox"
-                                    "{todo.checked}"
-                                }
-                            }
-                        }
-                    })
-                }
-
-                // filter toggle (show only if the list isn't empty)
-                {(!todos.is_empty()).then(||
-                    rsx!{
-                        footer {
-                            span {
-                                strong {"10"}
-                                span {"0 items left"}
-                            }
-                            ul {
-                                class: "filters"
-                            {[
-                                    ("All", "", FilterState::All),
-                                    ("Active", "active", FilterState::Active),
-                                    ("Completed", "completed", FilterState::Completed),
-                                ]
-                                .iter()
-                                .map(|(name, path, filter)| {
-                                    rsx!(
-                                        li {
-                                            class: "{name}"
-                                            a {
-                                                href: "{path}"
-                                                onclick: move |_| set_filter(filter.clone())
-                                                "{name}"
-                                            }
-                                        }
-                                    )
-                                })
-                            }}
-                        }
-                    }
-                )}
-            }
-
-
-            footer {
-                class: "info"
-                p {"Double-click to edit a todo"}
-                p {
-                    "Created by "
-                    a { "jkelleyrtp", href: "http://github.com/jkelleyrtp/" }
-                }
-                p {
-                    "Part of "
-                    a { "TodoMVC", href: "http://todomvc.com" }
-                }
-            }
-        }
-    ))
-};
-
-pub fn FilterToggles(cx: Context<()>) -> DomTree {
-    // let reducer = recoil::use_callback(&cx, || ());
-    // let items_left = recoil::use_atom_family(&cx, &TODOS, uuid::Uuid::new_v4());
-
-    let toggles = [
-        ("All", "", FilterState::All),
-        ("Active", "active", FilterState::Active),
-        ("Completed", "completed", FilterState::Completed),
-    ]
-    .iter()
-    .map(|(name, path, _filter)| {
-        rsx!(
-            li {
-                class: "{name}"
-                a {
-                    href: "{path}"
-                    // onclick: move |_| reducer.set_filter(&filter)
-                    "{name}"
-                }
-            }
-        )
-    });
-
-    // todo
-    let item_text = "";
-    let items_left = "";
-
-    cx.render(rsx! {
-        footer {
-            span {
-                strong {"{items_left}"}
-                span {"{item_text} left"}
-            }
-            ul {
-                class: "filters"
-                {toggles}
-            }
-        }
-    })
-}

+ 0 - 29
examples/_examples/listy.rs

@@ -1,29 +0,0 @@
-use dioxus_core as dioxus;
-use dioxus_core::prelude::*;
-use dioxus_html as dioxus_elements;
-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<()>) -> DomTree {
-    let items = (0..20).map(|f| {
-        rsx! {
-            li {"{f}"}
-        }
-    });
-
-    cx.render(rsx! {
-        div {
-            "list"
-            ul {
-                {items}
-            }
-        }
-    })
-}

+ 0 - 23
examples/_examples/many.rs

@@ -1,23 +0,0 @@
-use dioxus_core as dioxus;
-use dioxus_core::prelude::*;
-use dioxus_html as dioxus_elements;
-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(Example));
-}
-
-pub static Example: FC<()> = |cx, props| {
-    cx.render(rsx! {
-        div {
-            span {
-                class: "px-2 py-1 flex w-36 mt-4 items-center text-xs rounded-md font-semibold text-yellow-500 bg-yellow-100"
-                "DUE DATE : 18 JUN"
-            }
-        }
-    })
-};

+ 0 - 193
examples/_examples/model.rs

@@ -1,193 +0,0 @@
-//! Example: Calculator
-//! -------------------
-//!
-//! Some components benefit through the use of "Models". Models are a single block of encapsulated state that allow mutative
-//! methods to be performed on them. Dioxus exposes the ability to use the model pattern through the "use_model" hook.
-//!
-//! Models are commonly used in the "Model-View-Component" approach for building UI state.
-//!
-//! `use_model` is basically just a fancy wrapper around set_state, but saves a "working copy" of the new state behind a
-//! RefCell. To modify the working copy, you need to call "get_mut" which returns the RefMut. This makes it easy to write
-//! fully encapsulated apps that retain a certain feel of native Rusty-ness. A calculator app is a good example of when this
-//! is useful.
-//!
-//! Do note that "get_mut" returns a `RefMut` (a lock over a RefCell). If two `RefMut`s are held at the same time (ie in a loop)
-//! the RefCell will panic and crash. You can use `try_get_mut` or `.modify` to avoid this problem, or just not hold two
-//! RefMuts at the same time.
-
-use dioxus::events::on::*;
-use dioxus::prelude::*;
-use dioxus_core as dioxus;
-use dioxus_html as dioxus_elements;
-use dioxus_web::WebsysRenderer;
-
-const STYLE: &str = include_str!("../../../examples/assets/calculator.css");
-
-fn main() {
-    // Setup logging
-    wasm_logger::init(wasm_logger::Config::new(log::Level::Debug));
-    console_error_panic_hook::set_once();
-    // Run the app
-    wasm_bindgen_futures::spawn_local(WebsysRenderer::start(App));
-}
-
-static App: FC<()> = |cx, props| {
-    let state = use_model(&cx, || Calculator::new());
-
-    let clear_display = state.display_value.eq("0");
-    let clear_text = if clear_display { "C" } else { "AC" };
-    let formatted = state.formatted_display();
-
-    cx.render(rsx! {
-        div { id: "wrapper"
-            div { class: "app", style { "{STYLE}" }
-                div { class: "calculator", onkeypress: move |evt| state.get_mut().handle_keydown(evt),
-                    div { class: "calculator-display", "{formatted}"}
-                    div { class: "calculator-keypad"
-                        div { class: "input-keys"
-                            div { class: "function-keys"
-                                CalculatorKey { name: "key-clear", onclick: move |_| state.get_mut().clear_display(), "{clear_text}" }
-                                CalculatorKey { name: "key-sign", onclick: move |_| state.get_mut().toggle_sign(), "±"}
-                                CalculatorKey { name: "key-percent", onclick: move |_| state.get_mut().toggle_percent(), "%"}
-                            }
-                            div { class: "digit-keys"
-                                CalculatorKey { name: "key-0", onclick: move |_| state.get_mut().input_digit(0), "0" }
-                                CalculatorKey { name: "key-dot", onclick: move |_|  state.get_mut().input_dot(), "●" }
-                                {(1..10).map(move |k| rsx!{
-                                    CalculatorKey { key: "{k}", name: "key-{k}", onclick: move |_|  state.get_mut().input_digit(k), "{k}" }
-                                })}
-                            }
-                        }
-                        div { class: "operator-keys"
-                            CalculatorKey { name:"key-divide", onclick: move |_| state.get_mut().set_operator(Operator::Div), "÷" }
-                            CalculatorKey { name:"key-multiply", onclick: move |_| state.get_mut().set_operator(Operator::Mul), "×" }
-                            CalculatorKey { name:"key-subtract", onclick: move |_| state.get_mut().set_operator(Operator::Sub), "−" }
-                            CalculatorKey { name:"key-add", onclick: move |_| state.get_mut().set_operator(Operator::Add), "+" }
-                            CalculatorKey { name:"key-equals", onclick: move |_| state.get_mut().perform_operation(), "=" }
-                        }
-                    }
-                }
-            }
-        }
-    })
-};
-
-#[derive(Props)]
-struct CalculatorKeyProps<'a> {
-    name: &'static str,
-    onclick: &'a dyn Fn(MouseEvent),
-}
-
-fn CalculatorKey<'a, 'r>(cx: Context<'a, CalculatorKeyProps<'r>>) -> DomTree<'a> {
-    cx.render(rsx! {
-        button {
-            class: "calculator-key {cx.name}"
-            onclick: {cx.onclick}
-            {cx.children()}
-        }
-    })
-}
-
-#[derive(Clone)]
-struct Calculator {
-    display_value: String,
-    operator: Option<Operator>,
-    waiting_for_operand: bool,
-    cur_val: f64,
-}
-#[derive(Clone)]
-enum Operator {
-    Add,
-    Sub,
-    Mul,
-    Div,
-}
-
-impl Calculator {
-    fn new() -> Self {
-        Calculator {
-            display_value: "0".to_string(),
-            operator: None,
-            waiting_for_operand: false,
-            cur_val: 0.0,
-        }
-    }
-    fn formatted_display(&self) -> String {
-        use separator::Separatable;
-        self.display_value
-            .parse::<f64>()
-            .unwrap()
-            .separated_string()
-    }
-    fn clear_display(&mut self) {
-        self.display_value = "0".to_string();
-    }
-    fn input_digit(&mut self, digit: u8) {
-        let content = digit.to_string();
-        if self.waiting_for_operand || self.display_value == "0" {
-            self.waiting_for_operand = false;
-            self.display_value = content;
-        } else {
-            self.display_value.push_str(content.as_str());
-        }
-    }
-    fn input_dot(&mut self) {
-        if self.display_value.find(".").is_none() {
-            self.display_value.push_str(".");
-        }
-    }
-    fn perform_operation(&mut self) {
-        if let Some(op) = &self.operator {
-            let rhs = self.display_value.parse::<f64>().unwrap();
-            let new_val = match op {
-                Operator::Add => self.cur_val + rhs,
-                Operator::Sub => self.cur_val - rhs,
-                Operator::Mul => self.cur_val * rhs,
-                Operator::Div => self.cur_val / rhs,
-            };
-            self.cur_val = new_val;
-            self.display_value = new_val.to_string();
-            self.operator = None;
-        }
-    }
-    fn toggle_sign(&mut self) {
-        if self.display_value.starts_with("-") {
-            self.display_value = self.display_value.trim_start_matches("-").to_string();
-        } else {
-            self.display_value = format!("-{}", self.display_value);
-        }
-    }
-    fn toggle_percent(&mut self) {
-        self.display_value = (self.display_value.parse::<f64>().unwrap() / 100.0).to_string();
-    }
-    fn backspace(&mut self) {
-        if !self.display_value.as_str().eq("0") {
-            self.display_value.pop();
-        }
-    }
-    fn set_operator(&mut self, operator: Operator) {
-        self.operator = Some(operator);
-        self.cur_val = self.display_value.parse::<f64>().unwrap();
-        self.waiting_for_operand = true;
-    }
-    fn handle_keydown(&mut self, evt: KeyboardEvent) {
-        match evt.key_code() {
-            KeyCode::Backspace => self.backspace(),
-            KeyCode::_0 => self.input_digit(0),
-            KeyCode::_1 => self.input_digit(1),
-            KeyCode::_2 => self.input_digit(2),
-            KeyCode::_3 => self.input_digit(3),
-            KeyCode::_4 => self.input_digit(4),
-            KeyCode::_5 => self.input_digit(5),
-            KeyCode::_6 => self.input_digit(6),
-            KeyCode::_7 => self.input_digit(7),
-            KeyCode::_8 => self.input_digit(8),
-            KeyCode::_9 => self.input_digit(9),
-            KeyCode::Add => self.operator = Some(Operator::Add),
-            KeyCode::Subtract => self.operator = Some(Operator::Sub),
-            KeyCode::Divide => self.operator = Some(Operator::Div),
-            KeyCode::Multiply => self.operator = Some(Operator::Mul),
-            _ => {}
-        }
-    }
-}

+ 0 - 13
examples/_examples/props.rs

@@ -1,13 +0,0 @@
-use dioxus_core as dioxus;
-use dioxus_core::prelude::*;
-
-#[derive(Props)]
-struct MyProps<'a> {
-    blah: u128,
-    b: &'a (),
-}
-
-fn main() {
-    // let p = unsafe { MyProps {}.memoize(&MyProps {}) };
-    // dbg!(p);
-}

+ 0 - 20
examples/_examples/query.rs

@@ -1,20 +0,0 @@
-// use dioxus_core::prelude::*;
-// use dioxus_web::WebsysRenderer;
-
-// fn main() {
-//     wasm_bindgen_futures::spawn_local(WebsysRenderer::start(Example));
-// }
-
-// fn Example(cx: Context, props: ()) -> DomTree {
-//     let user_data = use_sql_query(&cx, USER_DATA_QUERY);
-
-//     cx.render(rsx! {
-//         h1 { "Hello, {username}"}
-//         button {
-//             "Delete user"
-//             onclick: move |_| user_data.delete()
-//         }
-//     })
-// }
-
-fn main() {}

+ 0 - 86
examples/_examples/rsxt.rs

@@ -1,86 +0,0 @@
-#![allow(non_snake_case)]
-use std::rc::Rc;
-
-use dioxus::{events::on::MouseEvent, prelude::*};
-use dioxus_core as dioxus;
-use dioxus_web::WebsysRenderer;
-use dioxus_html as dioxus_elements;
-
-
-fn main() {
-    wasm_logger::init(wasm_logger::Config::new(log::Level::Trace));
-    console_error_panic_hook::set_once();
-
-    wasm_bindgen_futures::spawn_local(async {
-        let props = ExampleProps {
-            initial_name: "..?",
-        };
-        WebsysRenderer::new_with_props(Example, props)
-            .run()
-            .await
-            .unwrap()
-    });
-}
-
-#[derive(PartialEq, Props)]
-struct ExampleProps {
-    initial_name: &'static str,
-}
-
-pub static Example: FC<ExampleProps> = |cx, props|{
-    let name = use_state(cx, move || cx.initial_name);
-
-    cx.render(rsx! {
-        div {
-            class: "py-12 px-4 text-center w-full max-w-2xl mx-auto"
-            span {
-                class: "text-sm font-semibold"
-                "Dioxus Example: Jack and Jill"
-            }
-            h2 {
-                class: "text-5xl mt-2 mb-6 leading-tight font-semibold font-heading"
-                "Hello, {name}"
-            }
-
-            CustomButton { name: "Jack!", handler: move |_| name.set("Jack") }
-            CustomButton { name: "Jill!", handler: move |_| name.set("Jill") }
-            CustomButton { name: "Bob!", handler: move |_| name.set("Bob")}
-            Placeholder {val: name}
-            Placeholder {val: name}
-        }
-    })
-};
-
-#[derive(Props)]
-struct ButtonProps<'src, F: Fn(MouseEvent)> {
-    name: &'src str,
-    handler: F,
-}
-
-fn CustomButton<'a, F: Fn(MouseEvent)>(cx: Context<'a, ButtonProps<'a, F>>) -> DomTree {
-    cx.render(rsx!{
-        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"
-            onmouseover: {&cx.handler}
-            "{cx.name}"
-        }
-    })
-}
-
-impl<F: Fn(MouseEvent)> PartialEq for ButtonProps<'_, F> {
-    fn eq(&self, other: &Self) -> bool {
-        false
-    }
-}
-
-#[derive(Props, PartialEq)]
-struct PlaceholderProps {
-    val: &'static str,
-}
-fn Placeholder(cx: Context<PlaceholderProps>) -> DomTree {
-    cx.render(rsx! {
-        div {
-            "child: {cx.val}"
-        }
-    })
-}

+ 0 - 126
examples/_examples/todomvc-nodeps.rs

@@ -1,126 +0,0 @@
-use std::{collections::HashMap, rc::Rc};
-
-use dioxus_core as dioxus;
-use dioxus_core::prelude::*;
-use dioxus_html as dioxus_elements;
-use dioxus_web::WebsysRenderer;
-
-static APP_STYLE: &'static str = include_str!("./todomvc/style.css");
-
-fn main() {
-    wasm_bindgen_futures::spawn_local(WebsysRenderer::start(App));
-}
-
-#[derive(PartialEq)]
-pub enum FilterState {
-    All,
-    Active,
-    Completed,
-}
-
-#[derive(Debug, PartialEq, Clone)]
-pub struct TodoItem {
-    pub id: uuid::Uuid,
-    pub checked: bool,
-    pub contents: String,
-}
-
-pub fn App(cx: Context<()>) -> DomTree {
-    let (draft, set_draft) = use_state_classic(cx, || "".to_string());
-    let (todos, set_todos) = use_state_classic(cx, || HashMap::<uuid::Uuid, Rc<TodoItem>>::new());
-    let (filter, set_filter) = use_state_classic(cx, || FilterState::All);
-
-    let filtered_todos = todos.iter().filter(move |(id, item)| match filter {
-        FilterState::All => true,
-        FilterState::Active => !item.checked,
-        FilterState::Completed => item.checked,
-    });
-    let items_left = filtered_todos.clone().count();
-    let item_text = match items_left {
-        1 => "item",
-        _ => "items",
-    };
-
-    cx.render(rsx! {
-        div { id: "app"
-            div {
-                header { class: "header"
-                    h1 {"todos"}
-                    input {
-                        class: "new-todo"
-                        placeholder: "What needs to be done?"
-                        value: "{draft}"
-                        oninput: move |evt| set_draft(evt.value())
-                    }
-                }
-
-                {filtered_todos.map(|(id, item)| {
-                    rsx!(TodoEntry {
-                        key: "{id}",
-                        item: item.clone()
-                    })
-                })}
-
-                // filter toggle (show only if the list isn't empty)
-                {(!todos.is_empty()).then(|| rsx!(
-                    footer {
-                        span {
-                            strong {"{items_left}"}
-                            span {"{item_text} left"}
-                        }
-                        ul {
-                            class: "filters"
-                            li { class: "All", a { href: "", onclick: move |_| set_filter(FilterState::All), "All" }}
-                            li { class: "Active", a { href: "active", onclick: move |_| set_filter(FilterState::Active), "Active" }}
-                            li { class: "Completed", a { href: "completed", onclick: move |_| set_filter(FilterState::Completed), "Completed" }}
-                        }
-                    }
-                ))}
-            }
-            // footer
-            footer {
-                class: "info"
-                p {"Double-click to edit a todo"}
-                p {
-                    "Created by "
-                    a { "jkelleyrtp", href: "http://github.com/jkelleyrtp/" }
-                }
-                p {
-                    "Part of "
-                    a { "TodoMVC", href: "http://todomvc.com" }
-                }
-            }
-        }
-    })
-}
-
-#[derive(PartialEq, Props)]
-pub struct TodoEntryProps {
-    item: Rc<TodoItem>,
-}
-
-pub fn TodoEntry(cx: Context<TodoEntryProps>) -> DomTree {
-    let (is_editing, set_is_editing) = use_state_classic(cx, || false);
-    let contents = "";
-    let todo = TodoItem {
-        checked: false,
-        contents: "asd".to_string(),
-        id: uuid::Uuid::new_v4(),
-    };
-
-    cx.render(rsx! (
-        li {
-            "{todo.id}"
-            input {
-                class: "toggle"
-                r#type: "checkbox"
-                "{todo.checked}"
-            }
-           {is_editing.then(|| rsx!{
-                input {
-                    value: "{contents}"
-                }
-            })}
-        }
-    ))
-}

+ 0 - 42
examples/_examples/todomvc/filtertoggles.rs

@@ -1,42 +0,0 @@
-use crate::recoil;
-use crate::state::{FilterState, TODOS};
-use dioxus_core::prelude::*;
-
-pub fn FilterToggles(cx: Context<()>) -> DomTree {
-    let reducer = recoil::use_callback(&cx, || ());
-    let items_left = recoil::use_atom_family(&cx, &TODOS, uuid::Uuid::new_v4());
-
-    let toggles = [
-        ("All", "", FilterState::All),
-        ("Active", "active", FilterState::Active),
-        ("Completed", "completed", FilterState::Completed),
-    ]
-    .iter()
-    .map(|(name, path, filter)| {
-        rsx!(li {
-            class: "{name}"
-            a {
-                "{name}"
-                href: "{path}"
-                onclick: move |_| reducer.set_filter(&filter)
-            }
-        })
-    });
-
-    // todo
-    let item_text = "";
-    let items_left = "";
-
-    cx.render(rsx! {
-        footer {
-            span {
-                strong {"{items_left}"}
-                span {"{item_text} left"}
-            }
-            ul {
-                class: "filters"
-                {toggles}
-            }
-        }
-    })
-}

+ 0 - 39
examples/_examples/todomvc/main.rs

@@ -1,39 +0,0 @@
-use dioxus_core as dioxus;
-use dioxus_html as dioxus_elements;
-use dioxus_web::{prelude::*, WebsysRenderer};
-
-// mod filtertoggles;
-// mod recoil;
-// mod state;
-// mod todoitem;
-// mod todolist;
-
-static APP_STYLE: &'static str = include_str!("./style.css");
-
-fn main() {
-    wasm_bindgen_futures::spawn_local(WebsysRenderer::start(|cx, props| {
-        cx.render(rsx! {
-            div {
-                id: "app"
-                // style { "{APP_STYLE}" }
-
-                // list
-                // todolist::TodoList {}
-
-                // footer
-                footer {
-                    class: "info"
-                    p {"Double-click to edit a todo"}
-                    p {
-                        "Created by "
-                        a { "jkelleyrtp", href: "http://github.com/jkelleyrtp/" }
-                    }
-                    p {
-                        "Part of "
-                        a { "TodoMVC", href: "http://todomvc.com" }
-                    }
-                }
-            }
-        })
-    }))
-}

+ 0 - 102
examples/_examples/todomvc/recoil.rs

@@ -1,102 +0,0 @@
-use dioxus_core::context::Context;
-
-pub struct RecoilContext<T: 'static> {
-    _inner: T,
-}
-
-impl<T: 'static> RecoilContext<T> {
-    /// Get the value of an atom. Returns a reference to the underlying data.
-
-    pub fn get(&self) {}
-
-    /// Replace an existing value with a new value
-    ///
-    /// This does not replace the value instantly, and all calls to "get" within the current scope will return
-    pub fn set(&self) {}
-
-    // Modify lets you modify the value in place. However, because there's no previous value around to compare
-    // the new one with, we are unable to memoize the change. As such, all downsteam users of this Atom will
-    // be updated, causing all subsrcibed components to re-render.
-    //
-    // This is fine for most values, but might not be performant when dealing with collections. For collections,
-    // use the "Family" variants as these will stay memoized for inserts, removals, and modifications.
-    //
-    // Note - like "set" this won't propogate instantly. Once all "gets" are dropped, only then will we run the
-    pub fn modify(&self) {}
-}
-
-pub fn use_callback<'a, G>(c: &Context<'a>, f: impl Fn() -> G) -> &'a RecoilContext<G> {
-    todo!()
-}
-
-pub fn use_atom<T: PartialEq, O>(c: &Context, t: &'static Atom<T>) -> O {
-    todo!()
-}
-pub fn use_batom<T: PartialEq, O>(c: &Context, t: impl Readable) -> O {
-    todo!()
-}
-
-pub trait Readable {}
-impl<T: PartialEq> Readable for &'static Atom<T> {}
-impl<K: PartialEq, V: PartialEq> Readable for &'static AtomFamily<K, V> {}
-
-pub fn use_atom_family<'a, K: PartialEq, V: PartialEq>(
-    c: &Context<'a>,
-    t: &'static AtomFamily<K, V>,
-    g: K,
-) -> &'a V {
-    todo!()
-}
-
-pub use atoms::{atom, Atom};
-pub use atoms::{atom_family, AtomFamily};
-mod atoms {
-
-    use super::*;
-    pub struct AtomBuilder<T: PartialEq> {
-        pub key: String,
-        pub manual_init: Option<Box<dyn Fn() -> T>>,
-        _never: std::marker::PhantomData<T>,
-    }
-
-    impl<T: PartialEq> AtomBuilder<T> {
-        pub fn new() -> Self {
-            Self {
-                key: uuid::Uuid::new_v4().to_string(),
-                manual_init: None,
-                _never: std::marker::PhantomData {},
-            }
-        }
-
-        pub fn init<A: Fn() -> T + 'static>(&mut self, f: A) {
-            self.manual_init = Some(Box::new(f));
-        }
-
-        pub fn set_key(&mut self, _key: &'static str) {}
-    }
-
-    pub struct atom<T: PartialEq>(pub fn(&mut AtomBuilder<T>) -> T);
-    pub type Atom<T: PartialEq> = atom<T>;
-
-    pub struct AtomFamilyBuilder<K, V> {
-        _never: std::marker::PhantomData<(K, V)>,
-    }
-
-    pub struct atom_family<K: PartialEq, V: PartialEq>(pub fn(&mut AtomFamilyBuilder<K, V>));
-    pub type AtomFamily<K: PartialEq, V: PartialEq> = atom_family<K, V>;
-}
-
-pub use selectors::selector;
-mod selectors {
-    pub struct SelectorBuilder<Out, const Built: bool> {
-        _p: std::marker::PhantomData<Out>,
-    }
-    impl<O> SelectorBuilder<O, false> {
-        pub fn getter(self, f: impl Fn(()) -> O) -> SelectorBuilder<O, true> {
-            todo!()
-            // std::rc::Rc::pin(value)
-            // todo!()
-        }
-    }
-    pub struct selector<O>(pub fn(SelectorBuilder<O, false>) -> SelectorBuilder<O, true>);
-}

+ 0 - 43
examples/_examples/todomvc/state.rs

@@ -1,43 +0,0 @@
-use crate::recoil::*;
-
-pub static TODOS: AtomFamily<uuid::Uuid, TodoItem> = atom_family(|_| {});
-pub static FILTER: Atom<FilterState> = atom(|_| FilterState::All);
-pub static SHOW_ALL_TODOS: selector<bool> = selector(|g| g.getter(|f| false));
-
-#[derive(PartialEq)]
-pub enum FilterState {
-    All,
-    Active,
-    Completed,
-}
-
-#[derive(Debug, PartialEq, Clone)]
-pub struct TodoItem {
-    pub id: uuid::Uuid,
-    pub checked: bool,
-    pub contents: String,
-}
-
-impl RecoilContext<()> {
-    pub fn add_todo(&self, contents: String) {}
-
-    pub fn remove_todo(&self, id: &uuid::Uuid) {
-        // TODOS.with().remove(id)
-    }
-
-    pub fn select_all_todos(&self) {}
-
-    pub fn toggle_todo(&self, id: &uuid::Uuid) {}
-
-    pub fn clear_completed(&self) {
-        // let (set, get) = (self.set, self.get);
-
-        // TOODS
-        //     .get(&cx)
-        //     .iter()
-        //     .filter(|(k, v)| v.checked)
-        //     .map(|(k, v)| TODOS.remove(&cx, k));
-    }
-
-    pub fn set_filter(&self, filter: &FilterState) {}
-}

+ 0 - 376
examples/_examples/todomvc/style.css

@@ -1,376 +0,0 @@
-html,
-body {
-	margin: 0;
-	padding: 0;
-}
-
-button {
-	margin: 0;
-	padding: 0;
-	border: 0;
-	background: none;
-	font-size: 100%;
-	vertical-align: baseline;
-	font-family: inherit;
-	font-weight: inherit;
-	color: inherit;
-	-webkit-appearance: none;
-	appearance: none;
-	-webkit-font-smoothing: antialiased;
-	-moz-osx-font-smoothing: grayscale;
-}
-
-body {
-	font: 14px 'Helvetica Neue', Helvetica, Arial, sans-serif;
-	line-height: 1.4em;
-	background: #f5f5f5;
-	color: #4d4d4d;
-	min-width: 230px;
-	max-width: 550px;
-	margin: 0 auto;
-	-webkit-font-smoothing: antialiased;
-	-moz-osx-font-smoothing: grayscale;
-	font-weight: 300;
-}
-
-:focus {
-	outline: 0;
-}
-
-.hidden {
-	display: none;
-}
-
-.todoapp {
-	background: #fff;
-	margin: 130px 0 40px 0;
-	position: relative;
-	box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.2),
-	            0 25px 50px 0 rgba(0, 0, 0, 0.1);
-}
-
-.todoapp input::-webkit-input-placeholder {
-	font-style: italic;
-	font-weight: 300;
-	color: #e6e6e6;
-}
-
-.todoapp input::-moz-placeholder {
-	font-style: italic;
-	font-weight: 300;
-	color: #e6e6e6;
-}
-
-.todoapp input::input-placeholder {
-	font-style: italic;
-	font-weight: 300;
-	color: #e6e6e6;
-}
-
-.todoapp h1 {
-	position: absolute;
-	top: -155px;
-	width: 100%;
-	font-size: 100px;
-	font-weight: 100;
-	text-align: center;
-	color: rgba(175, 47, 47, 0.15);
-	-webkit-text-rendering: optimizeLegibility;
-	-moz-text-rendering: optimizeLegibility;
-	text-rendering: optimizeLegibility;
-}
-
-.new-todo,
-.edit {
-	position: relative;
-	margin: 0;
-	width: 100%;
-	font-size: 24px;
-	font-family: inherit;
-	font-weight: inherit;
-	line-height: 1.4em;
-	border: 0;
-	color: inherit;
-	padding: 6px;
-	border: 1px solid #999;
-	box-shadow: inset 0 -1px 5px 0 rgba(0, 0, 0, 0.2);
-	box-sizing: border-box;
-	-webkit-font-smoothing: antialiased;
-	-moz-osx-font-smoothing: grayscale;
-}
-
-.new-todo {
-	padding: 16px 16px 16px 60px;
-	border: none;
-	background: rgba(0, 0, 0, 0.003);
-	box-shadow: inset 0 -2px 1px rgba(0,0,0,0.03);
-}
-
-.main {
-	position: relative;
-	z-index: 2;
-	border-top: 1px solid #e6e6e6;
-}
-
-.toggle-all {
-	text-align: center;
-	border: none; /* Mobile Safari */
-	opacity: 0;
-	position: absolute;
-}
-
-.toggle-all + label {
-	width: 60px;
-	height: 34px;
-	font-size: 0;
-	position: absolute;
-	top: -52px;
-	left: -13px;
-	-webkit-transform: rotate(90deg);
-	transform: rotate(90deg);
-}
-
-.toggle-all + label:before {
-	content: '❯';
-	font-size: 22px;
-	color: #e6e6e6;
-	padding: 10px 27px 10px 27px;
-}
-
-.toggle-all:checked + label:before {
-	color: #737373;
-}
-
-.todo-list {
-	margin: 0;
-	padding: 0;
-	list-style: none;
-}
-
-.todo-list li {
-	position: relative;
-	font-size: 24px;
-	border-bottom: 1px solid #ededed;
-}
-
-.todo-list li:last-child {
-	border-bottom: none;
-}
-
-.todo-list li.editing {
-	border-bottom: none;
-	padding: 0;
-}
-
-.todo-list li.editing .edit {
-	display: block;
-	width: 506px;
-	padding: 12px 16px;
-	margin: 0 0 0 43px;
-}
-
-.todo-list li.editing .view {
-	display: none;
-}
-
-.todo-list li .toggle {
-	text-align: center;
-	width: 40px;
-	/* auto, since non-WebKit browsers doesn't support input styling */
-	height: auto;
-	position: absolute;
-	top: 0;
-	bottom: 0;
-	margin: auto 0;
-	border: none; /* Mobile Safari */
-	-webkit-appearance: none;
-	appearance: none;
-}
-
-.todo-list li .toggle {
-	opacity: 0;
-}
-
-.todo-list li .toggle + label {
-	/*
-		Firefox requires `#` to be escaped - https://bugzilla.mozilla.org/show_bug.cgi?id=922433
-		IE and Edge requires *everything* to be escaped to render, so we do that instead of just the `#` - https://developer.microsoft.com/en-us/microsoft-edge/platform/issues/7157459/
-	*/
-	background-image: url('data:image/svg+xml;utf8,%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20width%3D%2240%22%20height%3D%2240%22%20viewBox%3D%22-10%20-18%20100%20135%22%3E%3Ccircle%20cx%3D%2250%22%20cy%3D%2250%22%20r%3D%2250%22%20fill%3D%22none%22%20stroke%3D%22%23ededed%22%20stroke-width%3D%223%22/%3E%3C/svg%3E');
-	background-repeat: no-repeat;
-	background-position: center left;
-}
-
-.todo-list li .toggle:checked + label {
-	background-image: url('data:image/svg+xml;utf8,%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20width%3D%2240%22%20height%3D%2240%22%20viewBox%3D%22-10%20-18%20100%20135%22%3E%3Ccircle%20cx%3D%2250%22%20cy%3D%2250%22%20r%3D%2250%22%20fill%3D%22none%22%20stroke%3D%22%23bddad5%22%20stroke-width%3D%223%22/%3E%3Cpath%20fill%3D%22%235dc2af%22%20d%3D%22M72%2025L42%2071%2027%2056l-4%204%2020%2020%2034-52z%22/%3E%3C/svg%3E');
-}
-
-.todo-list li label {
-	word-break: break-all;
-	padding: 15px 15px 15px 60px;
-	display: block;
-	line-height: 1.2;
-	transition: color 0.4s;
-}
-
-.todo-list li.completed label {
-	color: #d9d9d9;
-	text-decoration: line-through;
-}
-
-.todo-list li .destroy {
-	display: none;
-	position: absolute;
-	top: 0;
-	right: 10px;
-	bottom: 0;
-	width: 40px;
-	height: 40px;
-	margin: auto 0;
-	font-size: 30px;
-	color: #cc9a9a;
-	margin-bottom: 11px;
-	transition: color 0.2s ease-out;
-}
-
-.todo-list li .destroy:hover {
-	color: #af5b5e;
-}
-
-.todo-list li .destroy:after {
-	content: '×';
-}
-
-.todo-list li:hover .destroy {
-	display: block;
-}
-
-.todo-list li .edit {
-	display: none;
-}
-
-.todo-list li.editing:last-child {
-	margin-bottom: -1px;
-}
-
-.footer {
-	color: #777;
-	padding: 10px 15px;
-	height: 20px;
-	text-align: center;
-	border-top: 1px solid #e6e6e6;
-}
-
-.footer:before {
-	content: '';
-	position: absolute;
-	right: 0;
-	bottom: 0;
-	left: 0;
-	height: 50px;
-	overflow: hidden;
-	box-shadow: 0 1px 1px rgba(0, 0, 0, 0.2),
-	            0 8px 0 -3px #f6f6f6,
-	            0 9px 1px -3px rgba(0, 0, 0, 0.2),
-	            0 16px 0 -6px #f6f6f6,
-	            0 17px 2px -6px rgba(0, 0, 0, 0.2);
-}
-
-.todo-count {
-	float: left;
-	text-align: left;
-}
-
-.todo-count strong {
-	font-weight: 300;
-}
-
-.filters {
-	margin: 0;
-	padding: 0;
-	list-style: none;
-	position: absolute;
-	right: 0;
-	left: 0;
-}
-
-.filters li {
-	display: inline;
-}
-
-.filters li a {
-	color: inherit;
-	margin: 3px;
-	padding: 3px 7px;
-	text-decoration: none;
-	border: 1px solid transparent;
-	border-radius: 3px;
-}
-
-.filters li a:hover {
-	border-color: rgba(175, 47, 47, 0.1);
-}
-
-.filters li a.selected {
-	border-color: rgba(175, 47, 47, 0.2);
-}
-
-.clear-completed,
-html .clear-completed:active {
-	float: right;
-	position: relative;
-	line-height: 20px;
-	text-decoration: none;
-	cursor: pointer;
-}
-
-.clear-completed:hover {
-	text-decoration: underline;
-}
-
-.info {
-	margin: 65px auto 0;
-	color: #bfbfbf;
-	font-size: 10px;
-	text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5);
-	text-align: center;
-}
-
-.info p {
-	line-height: 1;
-}
-
-.info a {
-	color: inherit;
-	text-decoration: none;
-	font-weight: 400;
-}
-
-.info a:hover {
-	text-decoration: underline;
-}
-
-/*
-	Hack to remove background from Mobile Safari.
-	Can't use it globally since it destroys checkboxes in Firefox
-*/
-@media screen and (-webkit-min-device-pixel-ratio:0) {
-	.toggle-all,
-	.todo-list li .toggle {
-		background: none;
-	}
-
-	.todo-list li .toggle {
-		height: 40px;
-	}
-}
-
-@media (max-width: 430px) {
-	.footer {
-		height: 50px;
-	}
-
-	.filters {
-		bottom: 10px;
-	}
-}

+ 0 - 29
examples/_examples/todomvc/todoitem.rs

@@ -1,29 +0,0 @@
-use super::state::TODOS;
-use crate::recoil::use_atom_family;
-use dioxus_core::prelude::*;
-
-#[derive(PartialEq, Props)]
-pub struct TodoEntryProps {
-    id: uuid::Uuid,
-}
-
-pub fn TodoEntry(cx: Context, props: &TodoEntryProps) -> DomTree {
-    let (is_editing, set_is_editing) = use_state(cx, || false);
-    let todo = use_atom_family(&cx, &TODOS, cx.id);
-
-    cx.render(rsx! (
-        li {
-            "{todo.id}"
-            input {
-                class: "toggle"
-                type: "checkbox"
-                "{todo.checked}"
-            }
-            {is_editing.then(|| rsx!(
-                input {
-                    value: "{todo.contents}"
-                }
-            ))}
-        }
-    ))
-}

+ 0 - 49
examples/_examples/todomvc/todolist.rs

@@ -1,49 +0,0 @@
-use crate::{
-    filtertoggles,
-    recoil::use_atom,
-    state::{FilterState, TodoItem, FILTER, TODOS},
-    todoitem::TodoEntry,
-};
-use dioxus_core::prelude::*;
-
-pub fn TodoList(cx: Context<()>) -> DomTree {
-    let (draft, set_draft) = use_state(cx, || "".to_string());
-    let (todos, _) = use_state(cx, || Vec::<TodoItem>::new());
-    let filter = use_atom(&cx, &FILTER);
-
-    cx.render(rsx! {
-        div {
-            header {
-                class: "header"
-                h1 {"todos"}
-                input {
-                    class: "new-todo"
-                    placeholder: "What needs to be done?"
-                    value: "{draft}"
-                    oninput: move |evt| set_draft(evt.value)
-                }
-            }
-
-            { // list
-                todos
-                .iter()
-                .filter(|item| match filter {
-                    FilterState::All => true,
-                    FilterState::Active => !item.checked,
-                    FilterState::Completed => item.checked,
-                })
-                .map(|item| {
-                    rsx!(TodoEntry {
-                        key: "{order}",
-                        id: item.id,
-                    })
-                })
-            }
-
-            // filter toggle (show only if the list isn't empty)
-            {(!todos.is_empty()).then(||
-                rsx!( filtertoggles::FilterToggles {})
-            )}
-        }
-    })
-}

+ 0 - 167
examples/_examples/todomvc_simple.rs

@@ -1,167 +0,0 @@
-use std::{collections::HashMap, rc::Rc};
-
-use dioxus_core as dioxus;
-use dioxus_core::prelude::*;
-use dioxus_html as dioxus_elements;
-use dioxus_web::WebsysRenderer;
-
-static APP_STYLE: &'static str = include_str!("./todomvc/style.css");
-
-fn main() {
-    wasm_bindgen_futures::spawn_local(WebsysRenderer::start(App));
-}
-
-#[derive(PartialEq)]
-pub enum FilterState {
-    All,
-    Active,
-    Completed,
-}
-
-#[derive(Debug, PartialEq, Clone)]
-pub struct TodoItem {
-    pub id: uuid::Uuid,
-    pub checked: bool,
-    pub contents: String,
-}
-
-// =======================
-// Components
-// =======================
-pub fn App(cx: Context<()>) -> DomTree {
-    cx.render(rsx! {
-        div {
-            id: "app"
-
-            // list
-            TodoList {}
-
-            // footer
-            footer {
-                class: "info"
-                p {"Double-click to edit a todo"}
-                p {
-                    "Created by "
-                    a { "jkelleyrtp", href: "http://github.com/jkelleyrtp/" }
-                }
-                p {
-                    "Part of "
-                    a { "TodoMVC", href: "http://todomvc.com" }
-                }
-            }
-        }
-    })
-}
-
-pub fn TodoList(cx: Context<()>) -> DomTree {
-    let (draft, set_draft) = use_state_classic(cx, || "".to_string());
-    let (todos, set_todos) = use_state_classic(cx, || HashMap::<uuid::Uuid, Rc<TodoItem>>::new());
-    let (filter, set_filter) = use_state_classic(cx, || FilterState::All);
-
-    cx.render(rsx! {
-        div {
-            header {
-                class: "header"
-                h1 {"todos"}
-                input {
-                    class: "new-todo"
-                    placeholder: "What needs to be done?"
-                    value: "{draft}"
-                    oninput: move |evt| set_draft(evt.value())
-                }
-            }
-
-            { // list
-                todos
-                .iter()
-                .filter(|(id, item)| match filter {
-                    FilterState::All => true,
-                    FilterState::Active => !item.checked,
-                    FilterState::Completed => item.checked,
-                })
-                .map(|(id, item)| {
-                    // TodoEntry!();
-                    todo!()
-                    // rsx!(TodoEntry {
-                    //     key: "{order}",
-                    //     item: item.clone()
-                    // })
-                })
-            }
-
-            // filter toggle (show only if the list isn't empty)
-            {(!todos.is_empty()).then(||
-                rsx!( FilterToggles {})
-            )}
-        }
-    })
-}
-
-#[derive(PartialEq, Props)]
-pub struct TodoEntryProps {
-    item: Rc<TodoItem>,
-}
-
-pub fn TodoEntry(cx: Context<TodoEntryProps>) -> DomTree {
-    let (is_editing, set_is_editing) = use_state_classic(cx, || false);
-    let contents = "";
-    let todo = TodoItem {
-        checked: false,
-        contents: "asd".to_string(),
-        id: uuid::Uuid::new_v4(),
-    };
-
-    cx.render(rsx! (
-        li {
-            "{todo.id}"
-            input {
-                class: "toggle"
-                r#type: "checkbox"
-                "{todo.checked}"
-            }
-           {is_editing.then(|| rsx!{
-                input {
-                    value: "{contents}"
-                }
-            })}
-        }
-    ))
-}
-
-pub fn FilterToggles(cx: Context<()>) -> DomTree {
-    let toggles = [
-        ("All", "", FilterState::All),
-        ("Active", "active", FilterState::Active),
-        ("Completed", "completed", FilterState::Completed),
-    ]
-    .iter()
-    .map(|(name, path, filter)| {
-        rsx!(
-            li {
-                class: "{name}"
-                a {
-                    href: "{path}"
-                    // onclick: move |_| reducer.set_filter(&filter)
-                    "{name}"
-                }
-            }
-        )
-    });
-
-    // todo
-    let item_text = "";
-    let items_left = "";
-
-    cx.render(rsx! {
-        footer {
-            span {
-                strong {"{items_left}"}
-                span {"{item_text} left"}
-            }
-            ul {
-                class: "filters"
-                {toggles}
-            }
-        }
-    })
-}

+ 0 - 200
examples/_examples/todomvcsingle.rs

@@ -1,200 +0,0 @@
-//! Example: TODOVMC - One file
-//! ---------------------------
-//! This example shows how to build a one-file TODO MVC app with Dioxus and Recoil.
-//! This project is confined to a single file to showcase the suggested patterns
-//! for building a small but mighty UI with Dioxus without worrying about project structure.
-//!
-//! If you want an example on recommended project structure, check out the TodoMVC folder
-//!
-//! Here, we show to use Dioxus' Recoil state management solution to simplify app logic
-#![allow(non_snake_case)]
-use dioxus_core as dioxus;
-use dioxus_web::dioxus::prelude::*;
-
-use std::collections::HashMap;
-use uuid::Uuid;
-
-#[derive(PartialEq, Clone, Copy)]
-pub enum FilterState {
-    All,
-    Active,
-    Completed,
-}
-
-#[derive(Debug, PartialEq, Clone)]
-pub struct TodoItem {
-    pub id: Uuid,
-    pub checked: bool,
-    pub contents: String,
-}
-
-// Declare our global app state
-const TODO_LIST: AtomHashMap<Uuid, TodoItem> = |_| {};
-const FILTER: Atom<FilterState> = |_| FilterState::All;
-const TODOS_LEFT: Selector<usize> = |api| api.get(&TODO_LIST).len();
-
-// Implement a simple abstraction over sets/gets of multiple atoms
-struct TodoManager(RecoilApi);
-impl TodoManager {
-    fn add_todo(&self, contents: String) {
-        let item = TodoItem {
-            checked: false,
-            contents,
-            id: Uuid::new_v4(),
-        };
-        self.0.modify(&TODO_LIST, move |list| {
-            list.insert(item.id, item);
-        });
-    }
-    fn remove_todo(&self, id: &Uuid) {
-        self.0.modify(&TODO_LIST, move |list| {
-            list.remove(id);
-        })
-    }
-    fn select_all_todos(&self) {
-        self.0.modify(&TODO_LIST, move |list| {
-            for item in list.values_mut() {
-                item.checked = true;
-            }
-        })
-    }
-    fn toggle_todo(&self, id: &Uuid) {
-        self.0.modify(&TODO_LIST, move |list| {
-            list.get_mut(id).map(|item| item.checked = !item.checked)
-        });
-    }
-    fn clear_completed(&self) {
-        self.0.modify(&TODO_LIST, move |list| {
-            *list = list.drain().filter(|(_, item)| !item.checked).collect();
-        })
-    }
-    fn set_filter(&self, filter: &FilterState) {
-        self.0.modify(&FILTER, move |f| *f = *filter);
-    }
-}
-
-pub fn TodoList(cx: Context<()>) -> DomTree {
-    let draft = use_state(cx, || "".to_string());
-    let todos = use_read(&cx, &TODO_LIST);
-    let filter = use_read(&cx, &FILTER);
-
-    let todolist = todos
-        .values()
-        .filter(|item| match filter {
-            FilterState::All => true,
-            FilterState::Active => !item.checked,
-            FilterState::Completed => item.checked,
-        })
-        .map(|item| {
-            rsx!(TodoEntry {
-                key: "{order}",
-                id: item.id,
-            })
-        });
-
-    rsx! { in cx,
-        div {
-            header {
-                class: "header"
-                h1 {"todos"}
-                input {
-                    class: "new-todo"
-                    placeholder: "What needs to be done?"
-                    value: "{draft}"
-                    oninput: move |evt| draft.set(evt.value)
-                }
-            }
-            {todolist}
-
-            // rsx! accepts optionals, so we suggest the `then` method in place of ternary
-            {(!todos.is_empty()).then(|| rsx!( FilterToggles {}) )}
-        }
-    }
-}
-
-#[derive(PartialEq, Props)]
-pub struct TodoEntryProps {
-    id: Uuid,
-}
-
-pub fn TodoEntry(cx: Context, props: &TodoEntryProps) -> DomTree {
-    let (is_editing, set_is_editing) = use_state_classic(cx, || false);
-    let todo = use_read(&cx, &TODO_LIST).get(&cx.id).unwrap();
-
-    cx.render(rsx! (
-        li {
-            "{todo.id}"
-            input {
-                class: "toggle"
-                type: "checkbox"
-                "{todo.checked}"
-            }
-           {is_editing.then(|| rsx!(
-                input {
-                    value: "{todo.contents}"
-                }
-           ))}
-        }
-    ))
-}
-
-pub fn FilterToggles(cx: Context<()>) -> DomTree {
-    let reducer = TodoManager(use_recoil_api(cx));
-    let items_left = use_read(cx, &TODOS_LEFT);
-
-    let item_text = match items_left {
-        1 => "item",
-        _ => "items",
-    };
-
-    let toggles = rsx! {
-        ul {
-            class: "filters"
-            li { class: "All", a { href: "", onclick: move |_| reducer.set_filter(&FilterState::All), "All" }}
-            li { class: "Active", a { href: "active", onclick: move |_| reducer.set_filter(&FilterState::Active), "Active" }}
-            li { class: "Completed", a { href: "completed", onclick: move |_| reducer.set_filter(&FilterState::Completed), "Completed" }}
-        }
-    };
-
-    rsx! { in cx,
-        footer {
-            span {
-                strong {"{items_left}"}
-                span { "{item_text} left" }
-            }
-            {toggles}
-        }
-    }
-}
-
-pub fn Footer(cx: Context<()>) -> DomTree {
-    rsx! { in cx,
-        footer { class: "info"
-            p {"Double-click to edit a todo"}
-            p {
-                "Created by "
-                a { "jkelleyrtp", href: "http://github.com/jkelleyrtp/" }
-            }
-            p {
-                "Part of "
-                a { "TodoMVC", href: "http://todomvc.com" }
-            }
-        }
-    }
-}
-
-const APP_STYLE: &'static str = include_str!("./todomvc/style.css");
-
-fn App(cx: Context<()>) -> DomTree {
-    use_init_recoil_root(cx, |_| {});
-    rsx! { in cx,
-        div { id: "app"
-            TodoList {}
-            Footer {}
-        }
-    }
-}
-
-fn main() {
-    wasm_bindgen_futures::spawn_local(dioxus_web::WebsysRenderer::start(App));
-}

+ 0 - 47
examples/_examples/weather.rs

@@ -1,47 +0,0 @@
-//! basic example that renders a simple VNode to the page :)
-//!
-//!
-//!
-use dioxus_core::prelude::*;
-use dioxus_web::*;
-
-fn main() {
-    wasm_logger::init(wasm_logger::Config::new(log::Level::Debug));
-    console_error_panic_hook::set_once();
-
-    wasm_bindgen_futures::spawn_local(WebsysRenderer::start(|cx, props| {
-        cx.render(html! {
-            <div>
-                <div class="flex items-center justify-center flex-col">
-                    <div class="flex items-center justify-center">
-                        <div class="flex flex-col bg-white rounded p-4 w-full max-w-xs">
-                            // Title
-                            <div class="font-bold text-xl">
-                                "Jon's awesome site!!"
-                            </div>
-
-                            // Subtext / description
-                            <div class="text-sm text-gray-500">
-                                "He worked so hard on it :)"
-                            </div>
-
-                            <div class="flex flex-row items-center justify-center mt-6">
-                                // Main number
-                                <div class="font-medium text-6xl">
-                                    "1337"
-                                </div>
-                            </div>
-
-                            // Try another
-                            <div class="flex flex-row justify-between mt-6">
-                                // <a href=format!("http://localhost:8080/fib/{}", other_fib_to_try) class="underline">
-                                    "Legit made my own React"
-                                // </a>
-                            </div>
-                        </div>
-                    </div>
-                </div>
-            </div>
-        })
-    }));
-}

+ 2 - 2
examples/todomvc.rs

@@ -3,8 +3,8 @@ use dioxus::prelude::*;
 use im_rc::HashMap;
 use std::rc::Rc;
 
-fn main() -> anyhow::Result<()> {
-    dioxus::desktop::launch(App, |c| c)
+fn main() {
+    dioxus::desktop::launch(App, |c| c);
 }
 
 #[derive(PartialEq)]

+ 0 - 1
packages/core/examples/jsframework.rs

@@ -1,5 +1,4 @@
 use dioxus::events::on::MouseEvent;
-use dioxus::events::DioxusEvent;
 use dioxus_core as dioxus;
 use dioxus_core::prelude::*;
 use dioxus_core_macro::*;

+ 59 - 47
packages/core/src/context.rs

@@ -102,6 +102,10 @@ impl<'src> Context<'src> {
         self.scope.memoized_updater.clone()
     }
 
+    pub fn needs_update(&self) {
+        (self.scope.memoized_updater)()
+    }
+
     /// Schedule an update for any component given its ScopeId.
     ///
     /// A component's ScopeId can be obtained from `use_hook` or the [`Context::scope_id`] method.
@@ -178,65 +182,69 @@ impl<'src> Context<'src> {
     /// struct SharedState(&'static str);
     ///
     /// static App: FC<()> = |cx, props|{
-    ///     cx.use_provide_state(|| SharedState("world"));
+    ///     cx.provide_state(SharedState("world"));
     ///     rsx!(cx, Child {})
     /// }
     ///
     /// static Child: FC<()> = |cx, props|{
-    ///     let state = cx.use_consume_state::<SharedState>();
+    ///     let state = cx.consume_state::<SharedState>();
     ///     rsx!(cx, div { "hello {state.0}" })
     /// }
     /// ```
-    pub fn use_provide_state<T, F>(self, init: F) -> &'src Rc<T>
+    pub fn provide_state<T>(self, value: T)
     where
         T: 'static,
-        F: FnOnce() -> T,
     {
-        let is_initialized = self.use_hook(
-            |_| false,
-            |s| {
-                let i = *s;
-                *s = true;
-                i
-            },
-            |_| {},
-        );
-
-        if !is_initialized {
-            let existing = self
-                .scope
-                .shared_contexts
-                .borrow_mut()
-                .insert(TypeId::of::<T>(), Rc::new(init()));
+        self.scope
+            .shared_contexts
+            .borrow_mut()
+            .insert(TypeId::of::<T>(), Rc::new(value))
+            .map(|f| f.downcast::<T>().ok())
+            .flatten();
+    }
 
-            if existing.is_some() {
-                log::warn!(
-                    "A shared state was replaced with itself. \
-                    This is does not result in a panic, but is probably not what you are trying to do"
-                );
-            }
-        }
+    /// Try to retrive a SharedState with type T from the any parent Scope.
+    pub fn consume_state<T: 'static>(self) -> Option<Rc<T>> {
+        let getter = &self.scope.shared.get_shared_context;
+        let ty = TypeId::of::<T>();
+        let idx = self.scope.our_arena_idx;
+        getter(idx, ty).map(|f| f.downcast().unwrap())
+    }
 
-        self.use_consume_state().unwrap()
+    /// Create a new subtree with this scope as the root of the subtree.
+    ///
+    /// Each component has its own subtree ID - the root subtree has an ID of 0. This ID is used by the renderer to route
+    /// the mutations to the correct window/portal/subtree.
+    ///
+    /// This method
+    ///
+    /// # Example
+    ///
+    /// ```rust
+    /// static App: FC<()> = |cx, props| {
+    ///     todo!();
+    ///     rsx!(cx, div { "Subtree {id}"})
+    /// };
+    /// ```        
+    pub fn create_subtree(self) -> Option<u32> {
+        self.scope.new_subtree()
     }
 
-    /// Uses a context, storing the cached value around
-    ///
-    /// If a context is not found on the first search, then this call will be  "dud", always returning "None" even if a
-    /// context was added later. This allows using another hook as a fallback
-    ///
-    pub fn use_consume_state<T: 'static>(self) -> Option<&'src Rc<T>> {
-        struct UseContextHook<C>(Option<Rc<C>>);
-        self.use_hook(
-            move |_| {
-                let getter = &self.scope.shared.get_shared_context;
-                let ty = TypeId::of::<T>();
-                let idx = self.scope.our_arena_idx;
-                UseContextHook(getter(idx, ty).map(|f| f.downcast().unwrap()))
-            },
-            move |hook| hook.0.as_ref(),
-            |_| {},
-        )
+    /// Get the subtree ID that this scope belongs to.
+    ///
+    /// Each component has its own subtree ID - the root subtree has an ID of 0. This ID is used by the renderer to route
+    /// the mutations to the correct window/portal/subtree.
+    ///
+    /// # Example
+    ///
+    /// ```rust
+    /// static App: FC<()> = |cx, props| {
+    ///     let id = cx.get_current_subtree();
+    ///     rsx!(cx, div { "Subtree {id}"})
+    /// };
+    /// ```
+    pub fn get_current_subtree(self) -> u32 {
+        self.scope.subtree()
     }
 
     /// Store a value between renders
@@ -271,13 +279,17 @@ impl<'src> Context<'src> {
         Output: 'src,
         Init: FnOnce(usize) -> State,
         Run: FnOnce(&'src mut State) -> Output,
-        Cleanup: FnOnce(&mut State) + 'static,
+        Cleanup: FnOnce(Box<State>) + 'static,
     {
         // If the idx is the same as the hook length, then we need to add the current hook
         if self.scope.hooks.at_end() {
             self.scope.hooks.push_hook(
                 initializer(self.scope.hooks.len()),
-                Box::new(|raw| cleanup(raw.downcast_mut::<State>().unwrap())),
+                Box::new(|raw| {
+                    //
+                    let s = raw.downcast::<State>().unwrap();
+                    cleanup(s);
+                }),
             );
         }
 

+ 114 - 71
packages/core/src/diff.rs

@@ -221,18 +221,12 @@ impl<'bump> DiffMachine<'bump> {
             MountType::Replace { old } => {
                 if let Some(old_id) = old.try_mounted_id() {
                     self.mutations.replace_with(old_id, nodes_created as u32);
+                    self.remove_nodes(Some(old));
                 } else {
-                    let mut iter = RealChildIterator::new(old, self.vdom);
-                    let first = iter.next().unwrap();
-                    self.mutations
-                        .replace_with(first.mounted_id(), nodes_created as u32);
-                    self.remove_nodes(iter);
-                }
-            }
-
-            MountType::ReplaceByElementId { el } => {
-                if let Some(old) = el {
-                    self.mutations.replace_with(old, nodes_created as u32);
+                    if let Some(id) = self.find_first_element_id(old) {
+                        self.mutations.replace_with(id, nodes_created as u32);
+                    }
+                    self.remove_nodes(Some(old));
                 }
             }
 
@@ -326,13 +320,10 @@ impl<'bump> DiffMachine<'bump> {
         }
 
         for attr in *attributes {
-            self.mutations.set_attribute(attr);
+            self.mutations.set_attribute(attr, real_id.as_u64());
         }
 
         if !children.is_empty() {
-            // self.stack.element_id_stack.push(real_id);
-            // push our element_id onto the stack
-            // drop our element off the stack
             self.stack.create_children(children, MountType::Append);
         }
     }
@@ -352,12 +343,12 @@ impl<'bump> DiffMachine<'bump> {
         let parent_scope = self.vdom.get_scope(parent_idx).unwrap();
 
         let new_idx = self.vdom.insert_scope_with_key(|new_idx| {
-            let height = parent_scope.height + 1;
             Scope::new(
                 caller,
                 new_idx,
                 Some(parent_idx),
-                height,
+                parent_scope.height + 1,
+                parent_scope.subtree(),
                 ScopeChildren(vcomponent.children),
                 shared,
             )
@@ -379,11 +370,24 @@ impl<'bump> DiffMachine<'bump> {
 
         let new_component = self.vdom.get_scope_mut(new_idx).unwrap();
 
+        log::debug!("initializing component {:?}", new_idx);
+
         // Run the scope for one iteration to initialize it
         if new_component.run_scope(self.vdom) {
             // Take the node that was just generated from running the component
             let nextnode = new_component.frames.fin_head();
             self.stack.create_component(new_idx, nextnode);
+
+            //
+            /*
+            tree_item {
+
+            }
+
+            */
+            if new_component.is_subtree_root.get() {
+                self.stack.push_subtree();
+            }
         }
 
         // Finally, insert this scope as a seen node.
@@ -405,7 +409,7 @@ impl<'bump> DiffMachine<'bump> {
             (Fragment(old), Fragment(new)) => self.diff_fragment_nodes(old, new),
             (Anchor(old), Anchor(new)) => new.dom_id.set(old.dom_id.get()),
             (Suspended(old), Suspended(new)) => self.diff_suspended_nodes(old, new),
-            (Element(old), Element(new)) => self.diff_element_nodes(old, new, new_node),
+            (Element(old), Element(new)) => self.diff_element_nodes(old, new, old_node, new_node),
 
             // Anything else is just a basic replace and create
             (
@@ -420,9 +424,7 @@ impl<'bump> DiffMachine<'bump> {
     fn diff_text_nodes(&mut self, old: &'bump VText<'bump>, new: &'bump VText<'bump>) {
         if let Some(root) = old.dom_id.get() {
             if old.text != new.text {
-                self.mutations.push_root(root);
-                self.mutations.set_text(new.text);
-                self.mutations.pop();
+                self.mutations.set_text(new.text, root.as_u64());
             }
 
             new.dom_id.set(Some(root));
@@ -433,9 +435,10 @@ impl<'bump> DiffMachine<'bump> {
         &mut self,
         old: &'bump VElement<'bump>,
         new: &'bump VElement<'bump>,
+        old_node: &'bump VNode<'bump>,
         new_node: &'bump VNode<'bump>,
     ) {
-        let root = old.dom_id.get();
+        let root = old.dom_id.get().unwrap();
 
         // If the element type is completely different, the element needs to be re-rendered completely
         // This is an optimization React makes due to how users structure their code
@@ -446,32 +449,19 @@ impl<'bump> DiffMachine<'bump> {
             // issue is that we need the "vnode" but this method only has the velement
             self.stack.push_nodes_created(0);
             self.stack.push(DiffInstruction::Mount {
-                and: MountType::ReplaceByElementId {
-                    el: old.dom_id.get(),
-                },
+                and: MountType::Replace { old: old_node },
             });
             self.create_element_node(new, new_node);
             return;
         }
 
-        new.dom_id.set(root);
+        new.dom_id.set(Some(root));
 
         // todo: attributes currently rely on the element on top of the stack, but in theory, we only need the id of the
         // element to modify its attributes.
         // it would result in fewer instructions if we just set the id directly.
         // it would also clean up this code some, but that's not very important anyways
 
-        // Don't push the root if we don't have to
-        let mut has_comitted = false;
-        let mut please_commit = |edits: &mut Vec<DomEdit>| {
-            if !has_comitted {
-                has_comitted = true;
-                edits.push(PushRoot {
-                    root: root.unwrap().as_u64(),
-                });
-            }
-        };
-
         // Diff Attributes
         //
         // It's extraordinarily rare to have the number/order of attributes change
@@ -481,20 +471,17 @@ impl<'bump> DiffMachine<'bump> {
         if old.attributes.len() == new.attributes.len() {
             for (old_attr, new_attr) in old.attributes.iter().zip(new.attributes.iter()) {
                 if old_attr.value != new_attr.value {
-                    please_commit(&mut self.mutations.edits);
-                    self.mutations.set_attribute(new_attr);
+                    self.mutations.set_attribute(new_attr, root.as_u64());
                 } else if new_attr.is_volatile {
-                    please_commit(&mut self.mutations.edits);
-                    self.mutations.set_attribute(new_attr);
+                    self.mutations.set_attribute(new_attr, root.as_u64());
                 }
             }
         } else {
-            please_commit(&mut self.mutations.edits);
             for attribute in old.attributes {
-                self.mutations.remove_attribute(attribute);
+                self.mutations.remove_attribute(attribute, root.as_u64());
             }
             for attribute in new.attributes {
-                self.mutations.set_attribute(attribute)
+                self.mutations.set_attribute(attribute, root.as_u64())
             }
         }
 
@@ -512,31 +499,34 @@ impl<'bump> DiffMachine<'bump> {
             if old.listeners.len() == new.listeners.len() {
                 for (old_l, new_l) in old.listeners.iter().zip(new.listeners.iter()) {
                     if old_l.event != new_l.event {
-                        please_commit(&mut self.mutations.edits);
-                        self.mutations.remove_event_listener(old_l.event);
+                        self.mutations
+                            .remove_event_listener(old_l.event, root.as_u64());
                         self.mutations.new_event_listener(new_l, cur_scope_id);
                     }
                     new_l.mounted_node.set(old_l.mounted_node.get());
                     self.attach_listener_to_scope(new_l, scope);
                 }
             } else {
-                please_commit(&mut self.mutations.edits);
                 for listener in old.listeners {
-                    self.mutations.remove_event_listener(listener.event);
+                    self.mutations
+                        .remove_event_listener(listener.event, root.as_u64());
                 }
                 for listener in new.listeners {
-                    listener.mounted_node.set(root);
+                    listener.mounted_node.set(Some(root));
                     self.mutations.new_event_listener(listener, cur_scope_id);
                     self.attach_listener_to_scope(listener, scope);
                 }
             }
         }
 
-        if has_comitted {
-            self.mutations.pop();
+        if old.children.len() == 0 && new.children.len() != 0 {
+            self.mutations.edits.push(PushRoot {
+                root: root.as_u64(),
+            });
+            self.stack.create_children(new.children, MountType::Append);
+        } else {
+            self.diff_children(old.children, new.children);
         }
-
-        self.diff_children(old.children, new.children);
     }
 
     fn diff_component_nodes(
@@ -551,6 +541,7 @@ impl<'bump> DiffMachine<'bump> {
 
         // Make sure we're dealing with the same component (by function pointer)
         if old.user_fc == new.user_fc {
+            log::debug!("Diffing component {:?} - {:?}", new.user_fc, scope_addr);
             //
             self.stack.scope_stack.push(scope_addr);
 
@@ -559,7 +550,6 @@ impl<'bump> DiffMachine<'bump> {
 
             // make sure the component's caller function is up to date
             let scope = self.vdom.get_scope_mut(scope_addr).unwrap();
-
             scope.update_scope_dependencies(new.caller, ScopeChildren(new.children));
 
             // React doesn't automatically memoize, but we do.
@@ -574,8 +564,6 @@ impl<'bump> DiffMachine<'bump> {
             }
 
             self.stack.scope_stack.pop();
-
-            self.seen_scopes.insert(scope_addr);
         } else {
             self.stack
                 .create_node(new_node, MountType::Replace { old: old_node });
@@ -590,6 +578,9 @@ impl<'bump> DiffMachine<'bump> {
             return;
         }
 
+        debug_assert!(old.children.len() != 0);
+        debug_assert!(new.children.len() != 0);
+
         self.diff_children(old.children, new.children);
     }
 
@@ -622,20 +613,18 @@ impl<'bump> DiffMachine<'bump> {
         match (old, new) {
             ([], []) => {}
             ([], _) => {
+                // we need to push the
                 self.stack.create_children(new, MountType::Append);
             }
             (_, []) => {
-                for node in old {
-                    self.remove_nodes(Some(node));
-                }
+                self.remove_nodes(old);
             }
             ([VNode::Anchor(old_anchor)], [VNode::Anchor(new_anchor)]) => {
                 old_anchor.dom_id.set(new_anchor.dom_id.get());
             }
-            ([VNode::Anchor(anchor)], _) => {
-                let el = anchor.dom_id.get();
+            ([VNode::Anchor(_)], _) => {
                 self.stack
-                    .create_children(new, MountType::ReplaceByElementId { el });
+                    .create_children(new, MountType::Replace { old: &old[0] });
             }
             (_, [VNode::Anchor(_)]) => {
                 self.replace_and_create_many_with_one(old, &new[0]);
@@ -744,19 +733,63 @@ impl<'bump> DiffMachine<'bump> {
             Some(count) => count,
             None => return,
         };
-        log::debug!(
-            "Left offset, right offset, {}, {}",
-            left_offset,
-            right_offset,
-        );
+        // log::debug!(
+        //     "Left offset, right offset, {}, {}",
+        //     left_offset,
+        //     right_offset,
+        // );
 
+        // log::debug!("stack before lo is {:#?}", self.stack.instructions);
         // Ok, we now hopefully have a smaller range of children in the middle
         // within which to re-order nodes with the same keys, remove old nodes with
         // now-unused keys, and create new nodes with fresh keys.
-        self.diff_keyed_middle(
-            &old[left_offset..(old.len() - right_offset)],
-            &new[left_offset..(new.len() - right_offset)],
+
+        let old_middle = &old[left_offset..(old.len() - right_offset)];
+        let new_middle = &new[left_offset..(new.len() - right_offset)];
+
+        debug_assert!(
+            !((old_middle.len() == new_middle.len()) && old_middle.len() == 0),
+            "keyed children must have the same number of children"
         );
+        if new_middle.len() == 0 {
+            // remove the old elements
+            self.remove_nodes(old_middle);
+        } else if old_middle.len() == 0 {
+            // there were no old elements, so just create the new elements
+            // we need to find the right "foothold" though - we shouldnt use the "append" at all
+            if left_offset == 0 {
+                // insert at the beginning of the old list
+                let foothold = &old[old.len() - right_offset];
+                self.stack.create_children(
+                    new_middle,
+                    MountType::InsertBefore {
+                        other_node: foothold,
+                    },
+                );
+            } else if right_offset == 0 {
+                // insert at the end  the old list
+                let foothold = old.last().unwrap();
+                self.stack.create_children(
+                    new_middle,
+                    MountType::InsertAfter {
+                        other_node: foothold,
+                    },
+                );
+            } else {
+                // inserting in the middle
+                let foothold = &old[left_offset - 1];
+                self.stack.create_children(
+                    new_middle,
+                    MountType::InsertAfter {
+                        other_node: foothold,
+                    },
+                );
+            }
+        } else {
+            self.diff_keyed_middle(old_middle, new_middle);
+        }
+
+        log::debug!("stack after km is {:#?}", self.stack.instructions);
     }
 
     /// Diff both ends of the children that share keys.
@@ -882,6 +915,14 @@ impl<'bump> DiffMachine<'bump> {
         // If none of the old keys are reused by the new children, then we remove all the remaining old children and
         // create the new children afresh.
         if shared_keys.is_empty() {
+            log::debug!(
+                "no shared keys, replacing and creating many with many, {:#?}, {:#?}",
+                old,
+                new
+            );
+            log::debug!("old_key_to_old_index, {:#?}", old_key_to_old_index);
+            log::debug!("new_index_to_old_index, {:#?}", new_index_to_old_index);
+            log::debug!("shared_keys, {:#?}", shared_keys);
             self.replace_and_create_many_with_many(old, new);
             return;
         }
@@ -1075,9 +1116,11 @@ impl<'bump> DiffMachine<'bump> {
 
                 VNode::Component(c) => {
                     let scope_id = c.associated_scope.get().unwrap();
-                    let scope = self.vdom.get_scope(scope_id).unwrap();
+                    let scope = self.vdom.get_scope_mut(scope_id).unwrap();
                     let root = scope.root_node();
                     self.remove_nodes(Some(root));
+                    let mut s = self.vdom.try_remove(scope_id).unwrap();
+                    s.hooks.clear_hooks();
                 }
             }
         }

+ 8 - 2
packages/core/src/diff_stack.rs

@@ -30,13 +30,12 @@ pub enum MountType<'a> {
     Absorb,
     Append,
     Replace { old: &'a VNode<'a> },
-    ReplaceByElementId { el: Option<ElementId> },
     InsertAfter { other_node: &'a VNode<'a> },
     InsertBefore { other_node: &'a VNode<'a> },
 }
 
 pub(crate) struct DiffStack<'bump> {
-    instructions: Vec<DiffInstruction<'bump>>,
+    pub(crate) instructions: Vec<DiffInstruction<'bump>>,
     nodes_created_stack: SmallVec<[usize; 10]>,
     pub scope_stack: SmallVec<[ScopeId; 5]>,
 }
@@ -76,6 +75,13 @@ impl<'bump> DiffStack<'bump> {
         }
     }
 
+    pub fn push_subtree(&mut self) {
+        self.nodes_created_stack.push(0);
+        self.instructions.push(DiffInstruction::Mount {
+            and: MountType::Append,
+        });
+    }
+
     pub fn push_nodes_created(&mut self, count: usize) {
         self.nodes_created_stack.push(count);
     }

+ 0 - 1023
packages/core/src/events.old.rs

@@ -1,1023 +0,0 @@
-//! This module provides a set of common events for all Dioxus apps to target, regardless of host platform.
-//! -------------------------------------------------------------------------------------------------------
-//!
-//! 3rd party renderers are responsible for converting their native events into these virtual event types. Events might
-//! be heavy or need to interact through FFI, so the events themselves are designed to be lazy.
-use crate::{
-    innerlude::Listener,
-    innerlude::{ElementId, NodeFactory, ScopeId},
-};
-use bumpalo::boxed::Box as BumpBox;
-use std::{
-    any::Any,
-    cell::{Cell, RefCell},
-    fmt::Debug,
-    ops::Deref,
-    rc::Rc,
-    sync::Arc,
-};
-
-#[derive(Debug)]
-pub struct UserEvent {
-    /// The originator of the event trigger
-    pub scope: ScopeId,
-
-    /// The optional real node associated with the trigger
-    pub mounted_dom_id: Option<ElementId>,
-
-    /// The event type IE "onclick" or "onmouseover"
-    ///
-    /// The name that the renderer will use to mount the listener.
-    pub name: &'static str,
-
-    /// The type of event
-    pub event: SyntheticEvent,
-}
-
-pub enum SyntheticEvent {
-    AnimationEvent(on::AnimationEvent),
-    ClipboardEvent(on::ClipboardEvent),
-    CompositionEvent(on::CompositionEvent),
-    FocusEvent(on::FocusEvent),
-    FormEvent(on::FormEvent),
-    KeyboardEvent(on::KeyboardEvent),
-    GenericEvent(on::GenericEvent),
-    TouchEvent(on::TouchEvent),
-    ToggleEvent(on::ToggleEvent),
-    MediaEvent(on::MediaEvent),
-    MouseEvent(on::MouseEvent),
-    WheelEvent(on::WheelEvent),
-    SelectionEvent(on::SelectionEvent),
-    TransitionEvent(on::TransitionEvent),
-    PointerEvent(on::PointerEvent),
-}
-// ImageEvent(event_data::ImageEvent),
-
-impl std::fmt::Debug for SyntheticEvent {
-    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
-        let name = match self {
-            SyntheticEvent::ClipboardEvent(_) => "ClipboardEvent",
-            SyntheticEvent::CompositionEvent(_) => "CompositionEvent",
-            SyntheticEvent::KeyboardEvent(_) => "KeyboardEvent",
-            SyntheticEvent::FocusEvent(_) => "FocusEvent",
-            SyntheticEvent::FormEvent(_) => "FormEvent",
-            SyntheticEvent::SelectionEvent(_) => "SelectionEvent",
-            SyntheticEvent::TouchEvent(_) => "TouchEvent",
-            SyntheticEvent::WheelEvent(_) => "WheelEvent",
-            SyntheticEvent::MediaEvent(_) => "MediaEvent",
-            SyntheticEvent::AnimationEvent(_) => "AnimationEvent",
-            SyntheticEvent::TransitionEvent(_) => "TransitionEvent",
-            SyntheticEvent::ToggleEvent(_) => "ToggleEvent",
-            SyntheticEvent::MouseEvent(_) => "MouseEvent",
-            SyntheticEvent::PointerEvent(_) => "PointerEvent",
-            SyntheticEvent::GenericEvent(_) => "GenericEvent",
-        };
-
-        f.debug_struct("VirtualEvent").field("type", &name).finish()
-    }
-}
-
-/// Priority of Event Triggers.
-///
-/// Internally, Dioxus will abort work that's taking too long if new, more important, work arrives. Unlike React, Dioxus
-/// won't be afraid to pause work or flush changes to the RealDOM. This is called "cooperative scheduling". Some Renderers
-/// implement this form of scheduling internally, however Dioxus will perform its own scheduling as well.
-///
-/// The ultimate goal of the scheduler is to manage latency of changes, prioritizing "flashier" changes over "subtler" changes.
-///
-/// React has a 5-tier priority system. However, they break things into "Continuous" and "Discrete" priority. For now,
-/// we keep it simple, and just use a 3-tier priority system.
-///
-/// - NoPriority = 0
-/// - LowPriority = 1
-/// - NormalPriority = 2
-/// - UserBlocking = 3
-/// - HighPriority = 4
-/// - ImmediatePriority = 5
-///
-/// We still have a concept of discrete vs continuous though - discrete events won't be batched, but continuous events will.
-/// This means that multiple "scroll" events will be processed in a single frame, but multiple "click" events will be
-/// flushed before proceeding. Multiple discrete events is highly unlikely, though.
-#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, PartialOrd, Ord)]
-pub enum EventPriority {
-    /// Work that must be completed during the EventHandler phase.
-    ///
-    /// Currently this is reserved for controlled inputs.
-    Immediate = 3,
-
-    /// "High Priority" work will not interrupt other high priority work, but will interrupt medium and low priority work.
-    ///
-    /// This is typically reserved for things like user interaction.
-    ///
-    /// React calls these "discrete" events, but with an extra category of "user-blocking" (Immediate).
-    High = 2,
-
-    /// "Medium priority" work is generated by page events not triggered by the user. These types of events are less important
-    /// than "High Priority" events and will take presedence over low priority events.
-    ///
-    /// This is typically reserved for VirtualEvents that are not related to keyboard or mouse input.
-    ///
-    /// React calls these "continuous" events (e.g. mouse move, mouse wheel, touch move, etc).
-    Medium = 1,
-
-    /// "Low Priority" work will always be pre-empted unless the work is significantly delayed, in which case it will be
-    /// advanced to the front of the work queue until completed.
-    ///
-    /// The primary user of Low Priority work is the asynchronous work system (suspense).
-    ///
-    /// This is considered "idle" work or "background" work.
-    Low = 0,
-}
-
-pub(crate) fn event_meta(event: &UserEvent) -> (bool, EventPriority) {
-    use EventPriority::*;
-
-    match event.name {
-        // clipboard
-        "copy" | "cut" | "paste" => (true, Medium),
-
-        // Composition
-        "compositionend" | "compositionstart" | "compositionupdate" => (true, Low),
-
-        // Keyboard
-        "keydown" | "keypress" | "keyup" => (true, High),
-
-        // Focus
-        "focus" | "blur" => (true, Low),
-
-        // Form
-        "change" | "input" | "invalid" | "reset" | "submit" => (true, Medium),
-
-        // Mouse
-        "click" | "contextmenu" | "doubleclick" | "drag" | "dragend" | "dragenter" | "dragexit"
-        | "dragleave" | "dragover" | "dragstart" | "drop" | "mousedown" | "mouseenter"
-        | "mouseleave" | "mouseout" | "mouseover" | "mouseup" => (true, High),
-
-        "mousemove" => (false, Medium),
-
-        // Pointer
-        "pointerdown" | "pointermove" | "pointerup" | "pointercancel" | "gotpointercapture"
-        | "lostpointercapture" | "pointerenter" | "pointerleave" | "pointerover" | "pointerout" => {
-            (true, Medium)
-        }
-
-        // Selection
-        "select" | "touchcancel" | "touchend" => (true, Medium),
-
-        // Touch
-        "touchmove" | "touchstart" => (true, Medium),
-
-        // Wheel
-        "scroll" | "wheel" => (false, Medium),
-
-        // Media
-        "abort" | "canplay" | "canplaythrough" | "durationchange" | "emptied" | "encrypted"
-        | "ended" | "error" | "loadeddata" | "loadedmetadata" | "loadstart" | "pause" | "play"
-        | "playing" | "progress" | "ratechange" | "seeked" | "seeking" | "stalled" | "suspend"
-        | "timeupdate" | "volumechange" | "waiting" => (true, Medium),
-
-        // Animation
-        "animationstart" | "animationend" | "animationiteration" => (true, Medium),
-
-        // Transition
-        "transitionend" => (true, Medium),
-
-        // Toggle
-        "toggle" => (true, Medium),
-
-        _ => (true, Low),
-    }
-}
-
-pub use on::{
-    AnimationEvent, ClipboardEvent, CompositionEvent, FocusEvent, FormEvent, GenericEvent, KeyCode,
-    KeyboardEvent, MediaEvent, MouseEvent, PointerEvent, SelectionEvent, ToggleEvent, TouchEvent,
-    TransitionEvent, WheelEvent,
-};
-
-pub mod on {
-    //! This module defines the synthetic events that all Dioxus apps enable. No matter the platform, every dioxus renderer
-    //! will implement the same events and same behavior (bubbling, cancelation, etc).
-    //!
-    //! Synthetic events are immutable and wrapped in Arc. It is the intention for Dioxus renderers to re-use the underyling
-    //! Arc allocation through "get_mut"
-    //!
-    //! React recently dropped support for re-using event allocation and just passes the real event along.
-    use super::*;
-
-    macro_rules! event_directory {
-        ( $(
-            $( #[$attr:meta] )*
-            $eventdata:ident($wrapper:ident): [
-                $(
-                    $( #[$method_attr:meta] )*
-                    $name:ident
-                )*
-            ];
-        )* ) => {
-            $(
-                $(#[$attr])*
-                pub struct $wrapper(pub Arc<dyn $eventdata>);
-
-                // todo: derefing to the event is fine (and easy) but breaks some IDE stuff like (go to source)
-                // going to source in fact takes you to the source of Rc which is... less than useful
-                // Either we ask for this to be changed in Rust-analyzer or manually impkement the trait
-                impl Deref for $wrapper {
-                    type Target = Arc<dyn $eventdata>;
-                    fn deref(&self) -> &Self::Target {
-                        &self.0
-                    }
-                }
-
-                $(
-                    $(#[$method_attr])*
-                    pub fn $name<'a, F>(
-                        c: NodeFactory<'a>,
-                        mut callback: F,
-                    ) -> Listener<'a>
-                        where F: FnMut($wrapper) + 'a
-                    {
-                        let bump = &c.bump();
-
-                        let cb: &mut dyn FnMut(SyntheticEvent) = bump.alloc(move |evt: SyntheticEvent| match evt {
-                            SyntheticEvent::$wrapper(event) => callback(event),
-                            _ => unreachable!("Downcasted SyntheticEvent to wrong event type - this is an internal bug!")
-                        });
-
-                        let callback: BumpBox<dyn FnMut(SyntheticEvent) + 'a> = unsafe { BumpBox::from_raw(cb) };
-
-
-                        // ie oncopy
-                        let event_name = stringify!($name);
-
-                        // ie copy
-                        let shortname: &'static str = &event_name[2..];
-
-                        Listener {
-                            event: shortname,
-                            mounted_node: Cell::new(None),
-                            callback: RefCell::new(Some(callback)),
-                        }
-                    }
-                )*
-            )*
-        };
-    }
-
-    // The Dioxus Synthetic event system
-    event_directory! {
-        ClipboardEventInner(ClipboardEvent): [
-            /// Called when "copy"
-            oncopy
-
-            /// oncut
-            oncut
-
-            /// onpaste
-            onpaste
-        ];
-
-        CompositionEventInner(CompositionEvent): [
-            /// oncompositionend
-            oncompositionend
-
-            /// oncompositionstart
-            oncompositionstart
-
-            /// oncompositionupdate
-            oncompositionupdate
-        ];
-
-        KeyboardEventInner(KeyboardEvent): [
-            /// onkeydown
-            onkeydown
-
-            /// onkeypress
-            onkeypress
-
-            /// onkeyup
-            onkeyup
-        ];
-
-        FocusEventInner(FocusEvent): [
-            /// onfocus
-            onfocus
-
-            /// onblur
-            onblur
-        ];
-
-
-        FormEventInner(FormEvent): [
-            /// onchange
-            onchange
-
-            /// oninput handler
-            oninput
-
-            /// oninvalid
-            oninvalid
-
-            /// onreset
-            onreset
-
-            /// onsubmit
-            onsubmit
-        ];
-
-
-        /// A synthetic event that wraps a web-style [`MouseEvent`](https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent)
-        ///
-        ///
-        /// The MouseEvent interface represents events that occur due to the user interacting with a pointing device (such as a mouse).
-        ///
-        /// ## Trait implementation:
-        /// ```rust
-        ///     fn alt_key(&self) -> bool;
-        ///     fn button(&self) -> i16;
-        ///     fn buttons(&self) -> u16;
-        ///     fn client_x(&self) -> i32;
-        ///     fn client_y(&self) -> i32;
-        ///     fn ctrl_key(&self) -> bool;
-        ///     fn meta_key(&self) -> bool;
-        ///     fn page_x(&self) -> i32;
-        ///     fn page_y(&self) -> i32;
-        ///     fn screen_x(&self) -> i32;
-        ///     fn screen_y(&self) -> i32;
-        ///     fn shift_key(&self) -> bool;
-        ///     fn get_modifier_state(&self, key_code: &str) -> bool;
-        /// ```
-        ///
-        /// ## Event Handlers
-        /// - [`onclick`]
-        /// - [`oncontextmenu`]
-        /// - [`ondoubleclick`]
-        /// - [`ondrag`]
-        /// - [`ondragend`]
-        /// - [`ondragenter`]
-        /// - [`ondragexit`]
-        /// - [`ondragleave`]
-        /// - [`ondragover`]
-        /// - [`ondragstart`]
-        /// - [`ondrop`]
-        /// - [`onmousedown`]
-        /// - [`onmouseenter`]
-        /// - [`onmouseleave`]
-        /// - [`onmousemove`]
-        /// - [`onmouseout`]
-        /// - [`onmouseover`]
-        /// - [`onmouseup`]
-        MouseEventInner(MouseEvent): [
-            /// Execute a callback when a button is clicked.
-            ///
-            /// ## Description
-            ///
-            /// An element receives a click event when a pointing device button (such as a mouse's primary mouse button)
-            /// is both pressed and released while the pointer is located inside the element.
-            ///
-            /// - Bubbles: Yes
-            /// - Cancelable: Yes
-            /// - Interface: [`MouseEvent`]
-            ///
-            /// If the button is pressed on one element and the pointer is moved outside the element before the button
-            /// is released, the event is fired on the most specific ancestor element that contained both elements.
-            /// `click` fires after both the `mousedown` and `mouseup` events have fired, in that order.
-            ///
-            /// ## Example
-            /// ```
-            /// rsx!( button { "click me", onclick: move |_| log::info!("Clicked!`") } )
-            /// ```
-            ///
-            /// ## Reference
-            /// - https://www.w3schools.com/tags/ev_onclick.asp
-            /// - https://developer.mozilla.org/en-US/docs/Web/API/Element/click_event
-            onclick
-
-            /// oncontextmenu
-            oncontextmenu
-
-            /// ondoubleclick
-            ondoubleclick
-
-            /// ondrag
-            ondrag
-
-            /// ondragend
-            ondragend
-
-            /// ondragenter
-            ondragenter
-
-            /// ondragexit
-            ondragexit
-
-            /// ondragleave
-            ondragleave
-
-            /// ondragover
-            ondragover
-
-            /// ondragstart
-            ondragstart
-
-            /// ondrop
-            ondrop
-
-            /// onmousedown
-            onmousedown
-
-            /// onmouseenter
-            onmouseenter
-
-            /// onmouseleave
-            onmouseleave
-
-            /// onmousemove
-            onmousemove
-
-            /// onmouseout
-            onmouseout
-
-            ///
-            onscroll
-
-            /// onmouseover
-            ///
-            /// Triggered when the users's mouse hovers over an element.
-            onmouseover
-
-            /// onmouseup
-            onmouseup
-        ];
-
-        PointerEventInner(PointerEvent): [
-            /// pointerdown
-            onpointerdown
-
-            /// pointermove
-            onpointermove
-
-            /// pointerup
-            onpointerup
-
-            /// pointercancel
-            onpointercancel
-
-            /// gotpointercapture
-            ongotpointercapture
-
-            /// lostpointercapture
-            onlostpointercapture
-
-            /// pointerenter
-            onpointerenter
-
-            /// pointerleave
-            onpointerleave
-
-            /// pointerover
-            onpointerover
-
-            /// pointerout
-            onpointerout
-        ];
-
-        SelectionEventInner(SelectionEvent): [
-            /// onselect
-            onselect
-        ];
-
-        TouchEventInner(TouchEvent): [
-            /// ontouchcancel
-            ontouchcancel
-
-            /// ontouchend
-            ontouchend
-
-            /// ontouchmove
-            ontouchmove
-
-            /// ontouchstart
-            ontouchstart
-        ];
-
-        WheelEventInner(WheelEvent): [
-            ///
-            onwheel
-        ];
-
-        MediaEventInner(MediaEvent): [
-            ///abort
-            onabort
-
-            ///canplay
-            oncanplay
-
-            ///canplaythrough
-            oncanplaythrough
-
-            ///durationchange
-            ondurationchange
-
-            ///emptied
-            onemptied
-
-            ///encrypted
-            onencrypted
-
-            ///ended
-            onended
-
-            ///error
-            onerror
-
-            ///loadeddata
-            onloadeddata
-
-            ///loadedmetadata
-            onloadedmetadata
-
-            ///loadstart
-            onloadstart
-
-            ///pause
-            onpause
-
-            ///play
-            onplay
-
-            ///playing
-            onplaying
-
-            ///progress
-            onprogress
-
-            ///ratechange
-            onratechange
-
-            ///seeked
-            onseeked
-
-            ///seeking
-            onseeking
-
-            ///stalled
-            onstalled
-
-            ///suspend
-            onsuspend
-
-            ///timeupdate
-            ontimeupdate
-
-            ///volumechange
-            onvolumechange
-
-            ///waiting
-            onwaiting
-        ];
-
-        AnimationEventInner(AnimationEvent): [
-            /// onanimationstart
-            onanimationstart
-
-            /// onanimationend
-            onanimationend
-
-            /// onanimationiteration
-            onanimationiteration
-        ];
-
-        TransitionEventInner(TransitionEvent): [
-            ///
-            ontransitionend
-        ];
-
-        ToggleEventInner(ToggleEvent): [
-            ///
-            ontoggle
-        ];
-    }
-
-    pub struct GenericEvent(pub Arc<dyn GenericEventInner>);
-
-    pub trait GenericEventInner: Send + Sync {
-        /// Return a reference to the raw event. User will need to downcast the event to the right platform-specific type.
-        fn raw_event(&self) -> &dyn Any;
-        /// 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 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;
-
-        // Currently not supported because those no way we could possibly support it
-        // just cast the event to the right platform-specific type and return it
-        // /// Returns the event's path
-        // fn composed_path(&self) -> String;
-
-        /// Returns the element whose event listeners triggered the event
-        fn current_target(&self);
-        /// Returns whether or not the preventDefault method was called for the event
-        fn default_prevented(&self) -> bool;
-        /// Returns which phase of the event flow is currently being evaluated
-        fn event_phase(&self) -> u16;
-        /// Returns whether or not an event is trusted
-        fn is_trusted(&self) -> bool;
-        /// Cancels the event if it is cancelable, meaning that the default action that belongs to the event will
-        fn prevent_default(&self);
-        /// Prevents other listeners of the same event from being called
-        fn stop_immediate_propagation(&self);
-        /// Prevents further propagation of an event during event flow
-        fn stop_propagation(&self);
-        /// Returns the element that triggered the event
-        fn target(&self);
-        /// Returns the time (in milliseconds relative to the epoch) at which the event was created
-        fn time_stamp(&self) -> f64;
-    }
-
-    pub trait ClipboardEventInner: Send + Sync {
-        // DOMDataTransfer clipboardData
-    }
-
-    pub trait CompositionEventInner: Send + Sync {
-        fn data(&self) -> String;
-    }
-
-    pub trait KeyboardEventInner: Send + Sync {
-        fn alt_key(&self) -> bool;
-
-        fn char_code(&self) -> u32;
-
-        /// Identify which "key" was entered.
-        ///
-        /// This is the best method to use for all languages. They key gets mapped to a String sequence which you can match on.
-        /// The key isn't an enum because there are just so many context-dependent keys.
-        ///
-        /// A full list on which keys to use is available at:
-        /// <https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/key/Key_Values>
-        ///
-        /// # Example
-        ///
-        /// ```rust
-        /// match event.key().as_str() {
-        ///     "Esc" | "Escape" => {}
-        ///     "ArrowDown" => {}
-        ///     "ArrowLeft" => {}
-        ///      _ => {}
-        /// }
-        /// ```
-        ///
-        fn key(&self) -> String;
-
-        /// Get the key code as an enum Variant.
-        ///
-        /// This is intended for things like arrow keys, escape keys, function keys, and other non-international keys.
-        /// To match on unicode sequences, use the [`key`] method - this will return a string identifier instead of a limited enum.
-        ///
-        ///
-        /// ## Example
-        ///
-        /// ```rust
-        /// use dioxus::KeyCode;
-        /// match event.key_code() {
-        ///     KeyCode::Escape => {}
-        ///     KeyCode::LeftArrow => {}
-        ///     KeyCode::RightArrow => {}
-        ///     _ => {}
-        /// }
-        /// ```
-        ///
-        fn key_code(&self) -> KeyCode;
-
-        /// Check if the ctrl key was pressed down
-        fn ctrl_key(&self) -> bool;
-
-        fn get_modifier_state(&self, key_code: &str) -> bool;
-
-        fn locale(&self) -> String;
-        fn location(&self) -> usize;
-        fn meta_key(&self) -> bool;
-        fn repeat(&self) -> bool;
-        fn shift_key(&self) -> bool;
-        fn which(&self) -> usize;
-    }
-
-    pub trait FocusEventInner: Send + Sync {
-        /* DOMEventInner:  Send + SyncTarget relatedTarget */
-    }
-
-    pub trait FormEventInner: Send + Sync {
-        fn value(&self) -> String;
-    }
-
-    pub trait MouseEventInner: Send + Sync {
-        fn alt_key(&self) -> bool;
-        fn button(&self) -> i16;
-        fn buttons(&self) -> u16;
-        /// Get the X coordinate of the mouse relative to the window
-        fn client_x(&self) -> i32;
-        fn client_y(&self) -> i32;
-        fn ctrl_key(&self) -> bool;
-        fn meta_key(&self) -> bool;
-        fn page_x(&self) -> i32;
-        fn page_y(&self) -> i32;
-        fn screen_x(&self) -> i32;
-        fn screen_y(&self) -> i32;
-        fn shift_key(&self) -> bool;
-        fn get_modifier_state(&self, key_code: &str) -> bool;
-    }
-
-    pub trait PointerEventInner: Send + Sync {
-        // Mouse only
-        fn alt_key(&self) -> bool;
-        fn button(&self) -> i16;
-        fn buttons(&self) -> u16;
-        fn client_x(&self) -> i32;
-        fn client_y(&self) -> i32;
-        fn ctrl_key(&self) -> bool;
-        fn meta_key(&self) -> bool;
-        fn page_x(&self) -> i32;
-        fn page_y(&self) -> i32;
-        fn screen_x(&self) -> i32;
-        fn screen_y(&self) -> i32;
-        fn shift_key(&self) -> bool;
-        fn get_modifier_state(&self, key_code: &str) -> bool;
-        fn pointer_id(&self) -> i32;
-        fn width(&self) -> i32;
-        fn height(&self) -> i32;
-        fn pressure(&self) -> f32;
-        fn tangential_pressure(&self) -> f32;
-        fn tilt_x(&self) -> i32;
-        fn tilt_y(&self) -> i32;
-        fn twist(&self) -> i32;
-        fn pointer_type(&self) -> String;
-        fn is_primary(&self) -> bool;
-    }
-
-    pub trait SelectionEventInner: Send + Sync {}
-
-    pub trait TouchEventInner: Send + Sync {
-        fn alt_key(&self) -> bool;
-        fn ctrl_key(&self) -> bool;
-        fn meta_key(&self) -> bool;
-        fn shift_key(&self) -> bool;
-        fn get_modifier_state(&self, key_code: &str) -> bool;
-    }
-    // changedTouches: DOMTouchList,
-    // targetTouches: DOMTouchList,
-    // touches: DOMTouchList,
-
-    pub trait UIEventInner: Send + Sync {
-        fn detail(&self) -> i32;
-    }
-    // DOMAbstractView view
-
-    pub trait WheelEventInner: Send + Sync {
-        fn delta_mode(&self) -> u32;
-        fn delta_x(&self) -> f64;
-        fn delta_y(&self) -> f64;
-        fn delta_z(&self) -> f64;
-    }
-
-    pub trait MediaEventInner: Send + Sync {}
-
-    pub trait ImageEventInner: Send + Sync {
-        //     load error
-    }
-
-    pub trait AnimationEventInner: Send + Sync {
-        fn animation_name(&self) -> String;
-        fn pseudo_element(&self) -> String;
-        fn elapsed_time(&self) -> f32;
-    }
-
-    pub trait TransitionEventInner: Send + Sync {
-        fn property_name(&self) -> String;
-        fn pseudo_element(&self) -> String;
-        fn elapsed_time(&self) -> f32;
-    }
-
-    pub trait ToggleEventInner: Send + Sync {}
-
-    pub use util::KeyCode;
-    mod util {
-
-        #[derive(Clone, Copy)]
-        pub enum KeyCode {
-            Backspace = 8,
-            Tab = 9,
-            Enter = 13,
-            Shift = 16,
-            Ctrl = 17,
-            Alt = 18,
-            Pause = 19,
-            CapsLock = 20,
-            Escape = 27,
-            PageUp = 33,
-            PageDown = 34,
-            End = 35,
-            Home = 36,
-            LeftArrow = 37,
-            UpArrow = 38,
-            RightArrow = 39,
-            DownArrow = 40,
-            Insert = 45,
-            Delete = 46,
-            Num0 = 48,
-            Num1 = 49,
-            Num2 = 50,
-            Num3 = 51,
-            Num4 = 52,
-            Num5 = 53,
-            Num6 = 54,
-            Num7 = 55,
-            Num8 = 56,
-            Num9 = 57,
-            A = 65,
-            B = 66,
-            C = 67,
-            D = 68,
-            E = 69,
-            F = 70,
-            G = 71,
-            H = 72,
-            I = 73,
-            J = 74,
-            K = 75,
-            L = 76,
-            M = 77,
-            N = 78,
-            O = 79,
-            P = 80,
-            Q = 81,
-            R = 82,
-            S = 83,
-            T = 84,
-            U = 85,
-            V = 86,
-            W = 87,
-            X = 88,
-            Y = 89,
-            Z = 90,
-            LeftWindow = 91,
-            RightWindow = 92,
-            SelectKey = 93,
-            Numpad0 = 96,
-            Numpad1 = 97,
-            Numpad2 = 98,
-            Numpad3 = 99,
-            Numpad4 = 100,
-            Numpad5 = 101,
-            Numpad6 = 102,
-            Numpad7 = 103,
-            Numpad8 = 104,
-            Numpad9 = 105,
-            Multiply = 106,
-            Add = 107,
-            Subtract = 109,
-            DecimalPoint = 110,
-            Divide = 111,
-            F1 = 112,
-            F2 = 113,
-            F3 = 114,
-            F4 = 115,
-            F5 = 116,
-            F6 = 117,
-            F7 = 118,
-            F8 = 119,
-            F9 = 120,
-            F10 = 121,
-            F11 = 122,
-            F12 = 123,
-            NumLock = 144,
-            ScrollLock = 145,
-            Semicolon = 186,
-            EqualSign = 187,
-            Comma = 188,
-            Dash = 189,
-            Period = 190,
-            ForwardSlash = 191,
-            GraveAccent = 192,
-            OpenBracket = 219,
-            BackSlash = 220,
-            CloseBraket = 221,
-            SingleQuote = 222,
-            Unknown,
-        }
-
-        impl KeyCode {
-            pub fn from_raw_code(i: u8) -> Self {
-                use KeyCode::*;
-                match i {
-                    8 => Backspace,
-                    9 => Tab,
-                    13 => Enter,
-                    16 => Shift,
-                    17 => Ctrl,
-                    18 => Alt,
-                    19 => Pause,
-                    20 => CapsLock,
-                    27 => Escape,
-                    33 => PageUp,
-                    34 => PageDown,
-                    35 => End,
-                    36 => Home,
-                    37 => LeftArrow,
-                    38 => UpArrow,
-                    39 => RightArrow,
-                    40 => DownArrow,
-                    45 => Insert,
-                    46 => Delete,
-                    48 => Num0,
-                    49 => Num1,
-                    50 => Num2,
-                    51 => Num3,
-                    52 => Num4,
-                    53 => Num5,
-                    54 => Num6,
-                    55 => Num7,
-                    56 => Num8,
-                    57 => Num9,
-                    65 => A,
-                    66 => B,
-                    67 => C,
-                    68 => D,
-                    69 => E,
-                    70 => F,
-                    71 => G,
-                    72 => H,
-                    73 => I,
-                    74 => J,
-                    75 => K,
-                    76 => L,
-                    77 => M,
-                    78 => N,
-                    79 => O,
-                    80 => P,
-                    81 => Q,
-                    82 => R,
-                    83 => S,
-                    84 => T,
-                    85 => U,
-                    86 => V,
-                    87 => W,
-                    88 => X,
-                    89 => Y,
-                    90 => Z,
-                    91 => LeftWindow,
-                    92 => RightWindow,
-                    93 => SelectKey,
-                    96 => Numpad0,
-                    97 => Numpad1,
-                    98 => Numpad2,
-                    99 => Numpad3,
-                    100 => Numpad4,
-                    101 => Numpad5,
-                    102 => Numpad6,
-                    103 => Numpad7,
-                    104 => Numpad8,
-                    105 => Numpad9,
-                    106 => Multiply,
-                    107 => Add,
-                    109 => Subtract,
-                    110 => DecimalPoint,
-                    111 => Divide,
-                    112 => F1,
-                    113 => F2,
-                    114 => F3,
-                    115 => F4,
-                    116 => F5,
-                    117 => F6,
-                    118 => F7,
-                    119 => F8,
-                    120 => F9,
-                    121 => F10,
-                    122 => F11,
-                    123 => F12,
-                    144 => NumLock,
-                    145 => ScrollLock,
-                    186 => Semicolon,
-                    187 => EqualSign,
-                    188 => Comma,
-                    189 => Dash,
-                    190 => Period,
-                    191 => ForwardSlash,
-                    192 => GraveAccent,
-                    219 => OpenBracket,
-                    220 => BackSlash,
-                    221 => CloseBraket,
-                    222 => SingleQuote,
-                    _ => Unknown,
-                }
-            }
-
-            // get the raw code
-            pub fn raw_code(&self) -> u32 {
-                *self as u32
-            }
-        }
-    }
-}

+ 62 - 93
packages/core/src/events.rs

@@ -31,27 +31,33 @@ pub struct UserEvent {
     pub name: &'static str,
 
     /// The type of event
-    pub event: SyntheticEvent,
+    pub event: Box<dyn Any + Send>,
 }
 
-#[derive(Debug)]
-pub enum SyntheticEvent {
-    AnimationEvent(on::AnimationEvent),
-    ClipboardEvent(on::ClipboardEvent),
-    CompositionEvent(on::CompositionEvent),
-    FocusEvent(on::FocusEvent),
-    FormEvent(on::FormEvent),
-    KeyboardEvent(on::KeyboardEvent),
-    GenericEvent(DioxusEvent<()>),
-    TouchEvent(on::TouchEvent),
-    ToggleEvent(on::ToggleEvent),
-    MediaEvent(on::MediaEvent),
-    MouseEvent(on::MouseEvent),
-    WheelEvent(on::WheelEvent),
-    SelectionEvent(on::SelectionEvent),
-    TransitionEvent(on::TransitionEvent),
-    PointerEvent(on::PointerEvent),
-}
+struct EventInner {}
+
+// trait SyntheticEvent: Send + Debug {
+//     fn downcast(self: Box<Self>) -> Option<Box<dyn Any>>;
+// }
+
+// #[derive(Debug)]
+// pub enum SyntheticEvent {
+//     AnimationEvent(on::AnimationEvent),
+//     ClipboardEvent(on::ClipboardEvent),
+//     CompositionEvent(on::CompositionEvent),
+//     FocusEvent(on::FocusEvent),
+//     FormEvent(on::FormEvent),
+//     KeyboardEvent(on::KeyboardEvent),
+//     GenericEvent(DioxusEvent<()>),
+//     TouchEvent(on::TouchEvent),
+//     ToggleEvent(on::ToggleEvent),
+//     MediaEvent(on::MediaEvent),
+//     MouseEvent(on::MouseEvent),
+//     WheelEvent(on::WheelEvent),
+//     SelectionEvent(on::SelectionEvent),
+//     TransitionEvent(on::TransitionEvent),
+//     PointerEvent(on::PointerEvent),
+// }
 
 /// Priority of Event Triggers.
 ///
@@ -105,23 +111,7 @@ pub enum EventPriority {
     Low = 0,
 }
 
-#[derive(Debug)]
-pub struct DioxusEvent<T: Send + Sync> {
-    inner: T,
-    raw: Box<dyn Any + Send>,
-}
-
-impl<T: Send + Sync> DioxusEvent<T> {
-    pub fn new<F: Send + 'static>(inner: T, raw: F) -> Self {
-        let raw = Box::new(raw);
-        Self { inner, raw }
-    }
-
-    /// Return a reference to the raw event. User will need to downcast the event to the right platform-specific type.
-    pub fn native<E: 'static>(&self) -> Option<&E> {
-        self.raw.downcast_ref()
-    }
-
+impl EventInner {
     /*
     Not implemented!
 
@@ -200,20 +190,13 @@ impl<T: Send + Sync> DioxusEvent<T> {
     }
 }
 
-impl<T: Send + Sync> std::ops::Deref for DioxusEvent<T> {
-    type Target = T;
-
-    fn deref(&self) -> &Self::Target {
-        &self.inner
-    }
-}
-
 pub mod on {
     use super::*;
     macro_rules! event_directory {
         ( $(
             $( #[$attr:meta] )*
-            $eventdata:ident($wrapper:ident): [
+            $wrapper:ident: [
+            // $eventdata:ident($wrapper:ident): [
                 $(
                     $( #[$method_attr:meta] )*
                     $name:ident
@@ -221,20 +204,6 @@ pub mod on {
             ];
         )* ) => {
             $(
-                $(#[$attr])*
-                #[derive(Debug)]
-                pub struct $wrapper(pub DioxusEvent<$eventdata>);
-
-                // todo: derefing to the event is fine (and easy) but breaks some IDE stuff like (go to source)
-                // going to source in fact takes you to the source of Rc which is... less than useful
-                // Either we ask for this to be changed in Rust-analyzer or manually implement the trait
-                impl Deref for $wrapper {
-                    type Target = DioxusEvent<$eventdata>;
-                    fn deref(&self) -> &Self::Target {
-                        &self.0
-                    }
-                }
-
                 $(
                     $(#[$method_attr])*
                     pub fn $name<'a, F>(
@@ -248,12 +217,12 @@ pub mod on {
                         // we can't allocate unsized in bumpalo's box, so we need to craft the box manually
                         // safety: this is essentially the same as calling Box::new() but manually
                         // The box is attached to the lifetime of the bumpalo allocator
-                        let cb: &mut dyn FnMut(SyntheticEvent) = bump.alloc(move |evt: SyntheticEvent| match evt {
-                            SyntheticEvent::$wrapper(event) => callback(event),
-                            _ => unreachable!("Downcasted SyntheticEvent to wrong spcific event type - this is an internal bug!")
+                        let cb: &mut dyn FnMut(Box<dyn Any + Send>) = bump.alloc(move |evt: Box<dyn Any + Send>| {
+                            let event = evt.downcast::<$wrapper>().unwrap();
+                            callback(*event)
                         });
 
-                        let callback: BumpBox<dyn FnMut(SyntheticEvent) + 'a> = unsafe { BumpBox::from_raw(cb) };
+                        let callback: BumpBox<dyn FnMut(Box<dyn Any + Send>) + 'a> = unsafe { BumpBox::from_raw(cb) };
 
                         // ie oncopy
                         let event_name = stringify!($name);
@@ -274,7 +243,7 @@ pub mod on {
 
     // The Dioxus Synthetic event system
     event_directory! {
-        ClipboardEventInner(ClipboardEvent): [
+        ClipboardEvent: [
             /// Called when "copy"
             oncopy
 
@@ -285,7 +254,7 @@ pub mod on {
             onpaste
         ];
 
-        CompositionEventInner(CompositionEvent): [
+        CompositionEvent: [
             /// oncompositionend
             oncompositionend
 
@@ -296,7 +265,7 @@ pub mod on {
             oncompositionupdate
         ];
 
-        KeyboardEventInner(KeyboardEvent): [
+        KeyboardEvent: [
             /// onkeydown
             onkeydown
 
@@ -307,7 +276,7 @@ pub mod on {
             onkeyup
         ];
 
-        FocusEventInner(FocusEvent): [
+        FocusEvent: [
             /// onfocus
             onfocus
 
@@ -315,7 +284,7 @@ pub mod on {
             onblur
         ];
 
-        FormEventInner(FormEvent): [
+        FormEvent: [
             /// onchange
             onchange
 
@@ -373,7 +342,7 @@ pub mod on {
         /// - [`onmouseout`]
         /// - [`onmouseover`]
         /// - [`onmouseup`]
-        MouseEventInner(MouseEvent): [
+        MouseEvent: [
             /// Execute a callback when a button is clicked.
             ///
             /// ## Description
@@ -456,7 +425,7 @@ pub mod on {
             onmouseup
         ];
 
-        PointerEventInner(PointerEvent): [
+        PointerEvent: [
             /// pointerdown
             onpointerdown
 
@@ -488,12 +457,12 @@ pub mod on {
             onpointerout
         ];
 
-        SelectionEventInner(SelectionEvent): [
+        SelectionEvent: [
             /// onselect
             onselect
         ];
 
-        TouchEventInner(TouchEvent): [
+        TouchEvent: [
             /// ontouchcancel
             ontouchcancel
 
@@ -507,12 +476,12 @@ pub mod on {
             ontouchstart
         ];
 
-        WheelEventInner(WheelEvent): [
+        WheelEvent: [
             ///
             onwheel
         ];
 
-        MediaEventInner(MediaEvent): [
+        MediaEvent: [
             ///abort
             onabort
 
@@ -583,7 +552,7 @@ pub mod on {
             onwaiting
         ];
 
-        AnimationEventInner(AnimationEvent): [
+        AnimationEvent: [
             /// onanimationstart
             onanimationstart
 
@@ -594,12 +563,12 @@ pub mod on {
             onanimationiteration
         ];
 
-        TransitionEventInner(TransitionEvent): [
+        TransitionEvent: [
             ///
             ontransitionend
         ];
 
-        ToggleEventInner(ToggleEvent): [
+        ToggleEvent: [
             ///
             ontoggle
         ];
@@ -607,19 +576,19 @@ pub mod on {
 
     #[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
     #[derive(Debug)]
-    pub struct ClipboardEventInner(
+    pub struct ClipboardEvent(
         // DOMDataTransfer clipboardData
     );
 
     #[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
     #[derive(Debug)]
-    pub struct CompositionEventInner {
+    pub struct CompositionEvent {
         pub data: String,
     }
 
     #[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
     #[derive(Debug)]
-    pub struct KeyboardEventInner {
+    pub struct KeyboardEvent {
         pub char_code: u32,
 
         /// Identify which "key" was entered.
@@ -687,18 +656,18 @@ pub mod on {
 
     #[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
     #[derive(Debug)]
-    pub struct FocusEventInner {/* DOMEventInner:  Send + SyncTarget relatedTarget */}
+    pub struct FocusEvent {/* DOMEventInner:  Send + SyncTarget relatedTarget */}
 
     #[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
     #[derive(Debug)]
-    pub struct FormEventInner {
+    pub struct FormEvent {
         pub value: String,
-        /* DOMEventInner:  Send + SyncTarget relatedTarget */
+        /* DOMEvent:  Send + SyncTarget relatedTarget */
     }
 
     #[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
     #[derive(Debug)]
-    pub struct MouseEventInner {
+    pub struct MouseEvent {
         pub alt_key: bool,
         pub button: i16,
         pub buttons: u16,
@@ -716,7 +685,7 @@ pub mod on {
 
     #[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
     #[derive(Debug)]
-    pub struct PointerEventInner {
+    pub struct PointerEvent {
         // Mouse only
         pub alt_key: bool,
         pub button: i16,
@@ -745,11 +714,11 @@ pub mod on {
 
     #[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
     #[derive(Debug)]
-    pub struct SelectionEventInner {}
+    pub struct SelectionEvent {}
 
     #[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
     #[derive(Debug)]
-    pub struct TouchEventInner {
+    pub struct TouchEvent {
         pub alt_key: bool,
         pub ctrl_key: bool,
         pub meta_key: bool,
@@ -762,7 +731,7 @@ pub mod on {
 
     #[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
     #[derive(Debug)]
-    pub struct WheelEventInner {
+    pub struct WheelEvent {
         pub delta_mode: u32,
         pub delta_x: f64,
         pub delta_y: f64,
@@ -771,17 +740,17 @@ pub mod on {
 
     #[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
     #[derive(Debug)]
-    pub struct MediaEventInner {}
+    pub struct MediaEvent {}
 
     #[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
     #[derive(Debug)]
-    pub struct ImageEventInner {
+    pub struct ImageEvent {
         pub load_error: bool,
     }
 
     #[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
     #[derive(Debug)]
-    pub struct AnimationEventInner {
+    pub struct AnimationEvent {
         pub animation_name: String,
         pub pseudo_element: String,
         pub elapsed_time: f32,
@@ -789,7 +758,7 @@ pub mod on {
 
     #[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
     #[derive(Debug)]
-    pub struct TransitionEventInner {
+    pub struct TransitionEvent {
         pub property_name: String,
         pub pseudo_element: String,
         pub elapsed_time: f32,
@@ -797,7 +766,7 @@ pub mod on {
 
     #[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
     #[derive(Debug)]
-    pub struct ToggleEventInner {}
+    pub struct ToggleEvent {}
 }
 
 #[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]

+ 9 - 7
packages/core/src/hooklist.rs

@@ -12,7 +12,7 @@ use std::{
 /// Todo: this could use its very own bump arena, but that might be a tad overkill
 #[derive(Default)]
 pub(crate) struct HookList {
-    vals: RefCell<Vec<(UnsafeCell<Box<dyn Any>>, Box<dyn FnOnce(&mut dyn Any)>)>>,
+    vals: RefCell<Vec<(UnsafeCell<Box<dyn Any>>, Box<dyn FnOnce(Box<dyn Any>)>)>>,
     idx: Cell<usize>,
 }
 
@@ -35,7 +35,7 @@ impl HookList {
         self.idx.set(0);
     }
 
-    pub(crate) fn push_hook<T: 'static>(&self, new: T, cleanup: Box<dyn FnOnce(&mut dyn Any)>) {
+    pub(crate) fn push_hook<T: 'static>(&self, new: T, cleanup: Box<dyn FnOnce(Box<dyn Any>)>) {
         self.vals
             .borrow_mut()
             .push((UnsafeCell::new(Box::new(new)), cleanup))
@@ -52,14 +52,16 @@ impl HookList {
     pub(crate) fn at_end(&self) -> bool {
         self.cur_idx() >= self.len()
     }
-}
 
-// When the scope is dropped, we want to call the cleanup function for each of the hooks
-impl Drop for HookList {
-    fn drop(&mut self) {
+    pub fn clear_hooks(&mut self) {
         self.vals
             .borrow_mut()
             .drain(..)
-            .for_each(|(mut state, cleanup)| cleanup(state.get_mut()));
+            .for_each(|(mut state, cleanup)| {
+                //
+                let s: Box<dyn Any> = state.into_inner();
+                cleanup(s)
+                //
+            });
     }
 }

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

@@ -62,8 +62,8 @@ pub(crate) mod innerlude {
 
 pub use crate::innerlude::{
     Context, DioxusElement, DomEdit, DomTree, ElementId, EventPriority, LazyNodes, MountType,
-    Mutations, NodeFactory, Properties, SchedulerMsg, ScopeId, SuspendedContext, SyntheticEvent,
-    TaskHandle, TestDom, ThreadsafeVirtualDom, UserEvent, VNode, VirtualDom, FC,
+    Mutations, NodeFactory, Properties, SchedulerMsg, ScopeId, SuspendedContext, TaskHandle,
+    TestDom, ThreadsafeVirtualDom, UserEvent, VNode, VirtualDom, FC,
 };
 
 pub mod prelude {

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

@@ -90,16 +90,16 @@ impl<'a> Mutations<'a> {
             root: element_id,
         });
     }
-    pub(crate) fn remove_event_listener(&mut self, event: &'static str) {
-        self.edits.push(RemoveEventListener { event });
+    pub(crate) fn remove_event_listener(&mut self, event: &'static str, root: u64) {
+        self.edits.push(RemoveEventListener { event, root });
     }
 
     // modify
-    pub(crate) fn set_text(&mut self, text: &'a str) {
-        self.edits.push(SetText { text });
+    pub(crate) fn set_text(&mut self, text: &'a str, root: u64) {
+        self.edits.push(SetText { text, root });
     }
 
-    pub(crate) fn set_attribute(&mut self, attribute: &'a Attribute) {
+    pub(crate) fn set_attribute(&mut self, attribute: &'a Attribute, root: u64) {
         let Attribute {
             name,
             value,
@@ -111,12 +111,13 @@ impl<'a> Mutations<'a> {
             field: name,
             value,
             ns: *namespace,
+            root,
         });
     }
 
-    pub(crate) fn remove_attribute(&mut self, attribute: &Attribute) {
+    pub(crate) fn remove_attribute(&mut self, attribute: &Attribute, root: u64) {
         let name = attribute.name;
-        self.edits.push(RemoveAttribute { name });
+        self.edits.push(RemoveAttribute { name, root });
     }
 }
 
@@ -184,7 +185,6 @@ pub enum DomEdit<'bump> {
     Remove {
         root: u64,
     },
-
     CreateTextNode {
         text: &'bump str,
         root: u64,
@@ -207,17 +207,21 @@ pub enum DomEdit<'bump> {
         root: u64,
     },
     RemoveEventListener {
+        root: u64,
         event: &'static str,
     },
     SetText {
+        root: u64,
         text: &'bump str,
     },
     SetAttribute {
+        root: u64,
         field: &'static str,
         value: &'bump str,
         ns: Option<&'bump str>,
     },
     RemoveAttribute {
+        root: u64,
         name: &'static str,
     },
 }

+ 3 - 3
packages/core/src/nodes.rs

@@ -4,8 +4,7 @@
 //! cheap and *very* fast to construct - building a full tree should be quick.
 
 use crate::innerlude::{
-    empty_cell, Context, DomTree, ElementId, Properties, Scope, ScopeId, SuspendedContext,
-    SyntheticEvent, FC,
+    empty_cell, Context, DomTree, ElementId, Properties, Scope, ScopeId, SuspendedContext, FC,
 };
 use bumpalo::{boxed::Box as BumpBox, Bump};
 use std::{
@@ -271,7 +270,8 @@ pub struct Listener<'bump> {
     pub event: &'static str,
 
     /// The actual callback that the user specified
-    pub(crate) callback: RefCell<Option<BumpBox<'bump, dyn FnMut(SyntheticEvent) + 'bump>>>,
+    pub(crate) callback:
+        RefCell<Option<BumpBox<'bump, dyn FnMut(Box<dyn std::any::Any + Send>) + 'bump>>>,
 }
 
 /// Virtual Components for custom user-defined components

+ 2 - 2
packages/core/src/resources.rs

@@ -63,8 +63,8 @@ impl ResourcePool {
 
     /// return the id, freeing the space of the original node
     pub fn collect_garbage(&self, id: ElementId) {
-        todo!("garabge collection currently WIP")
-        // self.raw_elements.remove(id.0);
+        let els = unsafe { &mut *self.raw_elements.get() };
+        els.remove(id.0);
     }
 
     pub fn insert_scope_with_key(&self, f: impl FnOnce(ScopeId) -> Scope) -> ScopeId {

+ 41 - 14
packages/core/src/scheduler.rs

@@ -86,6 +86,7 @@ use std::{
 #[derive(Clone)]
 pub(crate) struct EventChannel {
     pub task_counter: Rc<Cell<u64>>,
+    pub cur_subtree: Rc<Cell<u32>>,
     pub sender: UnboundedSender<SchedulerMsg>,
     pub schedule_any_immediate: Rc<dyn Fn(ScopeId)>,
     pub submit_task: Rc<dyn Fn(FiberTask) -> TaskHandle>,
@@ -106,8 +107,6 @@ pub enum SchedulerMsg {
 }
 
 pub enum TaskMsg {
-    // SubmitTask(FiberTask, u64),
-    // SubmitTask(FiberTask, u64),
     ToggleTask(u64),
     PauseTask(u64),
     ResumeTask(u64),
@@ -178,13 +177,19 @@ impl Scheduler {
         let heuristics = HeuristicsEngine::new();
 
         let task_counter = Rc::new(Cell::new(0));
+        let cur_subtree = Rc::new(Cell::new(0));
 
         let channel = EventChannel {
+            cur_subtree,
             task_counter: task_counter.clone(),
             sender: sender.clone(),
             schedule_any_immediate: {
                 let sender = sender.clone();
-                Rc::new(move |id| sender.unbounded_send(SchedulerMsg::Immediate(id)).unwrap())
+                Rc::new(move |id| {
+                    //
+                    log::debug!("scheduling immedate! {:?}", id);
+                    sender.unbounded_send(SchedulerMsg::Immediate(id)).unwrap()
+                })
             },
             // todo: we want to get the futures out of the scheduler message
             // the scheduler message should be send/sync
@@ -319,6 +324,9 @@ impl Scheduler {
     unsafe fn load_work(&mut self) -> SavedDiffWork<'static> {
         self.saved_state.take().unwrap().extend()
     }
+    pub fn handle_task(&mut self, evt: TaskMsg) {
+        //
+    }
 
     pub fn handle_channel_msg(&mut self, msg: SchedulerMsg) {
         match msg {
@@ -370,23 +378,28 @@ impl Scheduler {
         if machine.stack.is_empty() {
             let shared = self.pool.clone();
 
+            self.dirty_scopes
+                .retain(|id| shared.get_scope(*id).is_some());
             self.dirty_scopes.sort_by(|a, b| {
                 let h1 = shared.get_scope(*a).unwrap().height;
                 let h2 = shared.get_scope(*b).unwrap().height;
-                h1.cmp(&h2)
+                h1.cmp(&h2).reverse()
             });
 
             if let Some(scopeid) = self.dirty_scopes.pop() {
-                log::info!("handlng dirty scope {:#?}", scopeid);
+                log::info!("handlng dirty scope {:?}", scopeid);
                 if !ran_scopes.contains(&scopeid) {
                     ran_scopes.insert(scopeid);
-
-                    let mut component = self.pool.get_scope_mut(scopeid).unwrap();
-                    if component.run_scope(&self.pool) {
-                        let (old, new) = (component.frames.wip_head(), component.frames.fin_head());
-                        // let (old, new) = (component.frames.wip_head(), component.frames.fin_head());
-                        machine.stack.scope_stack.push(scopeid);
-                        machine.stack.push(DiffInstruction::Diff { new, old });
+                    log::debug!("about to run scope {:?}", scopeid);
+
+                    if let Some(component) = self.pool.get_scope_mut(scopeid) {
+                        if component.run_scope(&self.pool) {
+                            let (old, new) =
+                                (component.frames.wip_head(), component.frames.fin_head());
+                            // let (old, new) = (component.frames.wip_head(), component.frames.fin_head());
+                            machine.stack.scope_stack.push(scopeid);
+                            machine.stack.push(DiffInstruction::Diff { new, old });
+                        }
                     }
                 }
             }
@@ -477,6 +490,18 @@ impl Scheduler {
         let mut committed_mutations = Vec::<Mutations<'static>>::new();
 
         while self.has_any_work() {
+            while let Ok(Some(msg)) = self.receiver.try_next() {
+                match msg {
+                    SchedulerMsg::Task(t) => todo!(),
+                    SchedulerMsg::Immediate(im) => {
+                        self.dirty_scopes.insert(im);
+                    }
+                    SchedulerMsg::UiEvent(evt) => {
+                        self.ui_events.push_back(evt);
+                    }
+                }
+            }
+
             // switch our priority, pop off any work
             while let Some(event) = self.ui_events.pop_front() {
                 if let Some(scope) = self.pool.get_scope_mut(event.scope) {
@@ -506,8 +531,6 @@ impl Scheduler {
             }
         }
 
-        log::debug!("work with deadline completed: {:#?}", committed_mutations);
-
         committed_mutations
     }
 
@@ -546,6 +569,8 @@ impl Scheduler {
             .get_scope_mut(base_scope)
             .expect("The base scope should never be moved");
 
+        log::debug!("rebuild {:?}", base_scope);
+
         // We run the component. If it succeeds, then we can diff it and add the changes to the dom.
         if cur_component.run_scope(&self.pool) {
             diff_machine
@@ -572,6 +597,8 @@ impl Scheduler {
             .get_scope_mut(base_scope)
             .expect("The base scope should never be moved");
 
+        log::debug!("hard diff {:?}", base_scope);
+
         if cur_component.run_scope(&self.pool) {
             let mut diff_machine = DiffMachine::new(Mutations::new(), &mut self.pool);
             diff_machine.cfg.force_diff = true;

+ 37 - 1
packages/core/src/scope.rs

@@ -2,7 +2,7 @@ use crate::innerlude::*;
 use fxhash::FxHashMap;
 use std::{
     any::{Any, TypeId},
-    cell::RefCell,
+    cell::{Cell, RefCell},
     collections::HashMap,
     future::Future,
     pin::Pin,
@@ -23,6 +23,8 @@ pub struct Scope {
     pub(crate) parent_idx: Option<ScopeId>,
     pub(crate) our_arena_idx: ScopeId,
     pub(crate) height: u32,
+    pub(crate) subtree: Cell<u32>,
+    pub(crate) is_subtree_root: Cell<bool>,
 
     // Nodes
     pub(crate) frames: ActiveFrame,
@@ -71,6 +73,36 @@ impl Scope {
         self.frames.fin_head()
     }
 
+    /// Get the subtree ID that this scope belongs to.
+    ///
+    /// Each component has its own subtree ID - the root subtree has an ID of 0. This ID is used by the renderer to route
+    /// the mutations to the correct window/portal/subtree.
+    ///
+    ///
+    /// # Example
+    ///
+    /// ```rust
+    /// let mut dom = VirtualDom::new(|cx, props|cx.render(rsx!{ div {} }));
+    /// dom.rebuild();
+    ///
+    /// let base = dom.base_scope();
+    ///
+    /// assert_eq!(base.subtree(), 0);
+    /// ```
+    pub fn subtree(&self) -> u32 {
+        self.subtree.get()
+    }
+
+    pub(crate) fn new_subtree(&self) -> Option<u32> {
+        if self.is_subtree_root.get() {
+            None
+        } else {
+            let cur = self.shared.cur_subtree.get();
+            self.shared.cur_subtree.set(cur + 1);
+            Some(cur)
+        }
+    }
+
     /// Get the height of this Scope - IE the number of scopes above it.
     ///
     /// A Scope with a height of `0` is the root scope - there are no other scopes above it.
@@ -146,6 +178,7 @@ impl Scope {
         our_arena_idx: ScopeId,
         parent_idx: Option<ScopeId>,
         height: u32,
+        subtree: u32,
         child_nodes: ScopeChildren,
         shared: EventChannel,
     ) -> Self {
@@ -168,6 +201,8 @@ impl Scope {
             parent_idx,
             our_arena_idx,
             height,
+            subtree: Cell::new(subtree),
+            is_subtree_root: Cell::new(false),
 
             frames: ActiveFrame::new(),
             hooks: Default::default(),
@@ -183,6 +218,7 @@ impl Scope {
         caller: &'creator_node dyn for<'b> Fn(&'b Scope) -> DomTree<'b>,
         child_nodes: ScopeChildren,
     ) {
+        log::debug!("Updating scope dependencies {:?}", self.our_arena_idx);
         let caller = caller as *const _;
         self.caller = unsafe { std::mem::transmute(caller) };
 

+ 5 - 20
packages/core/src/virtual_dom.rs

@@ -156,6 +156,7 @@ impl VirtualDom {
                 myidx,
                 None,
                 0,
+                0,
                 ScopeChildren(&[]),
                 scheduler.pool.channel.clone(),
             )
@@ -359,25 +360,21 @@ impl VirtualDom {
     /// Waits for the scheduler to have work
     /// This lets us poll async tasks during idle periods without blocking the main thread.
     pub async fn wait_for_work(&mut self) {
+        // todo: poll the events once even if there is work to do to prevent starvation
         if self.scheduler.has_any_work() {
-            log::debug!("No need to wait for work, we already have some");
             return;
         }
 
-        log::debug!("No active work.... waiting for some...");
         use futures_util::StreamExt;
 
-        // right now this won't poll events if there is ongoing work
-        // in the future we want to prioritize some events over ongoing work
-        // this is coming in the "priorities" PR
-
         // Wait for any new events if we have nothing to do
-        // todo: poll the events once even if there is work to do to prevent starvation
         futures_util::select! {
             _ = self.scheduler.async_tasks.next() => {}
             msg = self.scheduler.receiver.next() => {
                 match msg.unwrap() {
-                    SchedulerMsg::Task(t) => todo!(),
+                    SchedulerMsg::Task(t) => {
+                        self.scheduler.handle_task(t);
+                    },
                     SchedulerMsg::Immediate(im) => {
                         self.scheduler.dirty_scopes.insert(im);
                     }
@@ -387,18 +384,6 @@ impl VirtualDom {
                 }
             },
         }
-
-        while let Ok(Some(msg)) = self.scheduler.receiver.try_next() {
-            match msg {
-                SchedulerMsg::Task(t) => todo!(),
-                SchedulerMsg::Immediate(im) => {
-                    self.scheduler.dirty_scopes.insert(im);
-                }
-                SchedulerMsg::UiEvent(evt) => {
-                    self.scheduler.ui_events.push_back(evt);
-                }
-            }
-        }
     }
 }
 

+ 4 - 7
packages/core/tests/diffing.rs

@@ -45,13 +45,10 @@ fn html_and_rsx_generate_the_same_output() {
 
     assert_eq!(
         change.edits,
-        [
-            PushRoot { root: 1 },
-            SetText {
-                text: "Goodbye world"
-            },
-            PopRoot
-        ]
+        [SetText {
+            text: "Goodbye world",
+            root: 1
+        },]
     );
 }
 

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

@@ -18,12 +18,12 @@ fn shared_state_test() {
     struct MySharedState(&'static str);
 
     static App: FC<()> = |cx, props| {
-        cx.use_provide_state(|| MySharedState("world!"));
+        cx.provide_state(MySharedState("world!"));
         rsx!(cx, Child {})
     };
 
     static Child: FC<()> = |cx, props| {
-        let shared = cx.use_consume_state::<MySharedState>()?;
+        let shared = cx.consume_state::<MySharedState>()?;
         rsx!(cx, "Hello, {shared.0}")
     };
 

+ 1 - 1
packages/desktop/src/desktop_context.rs

@@ -54,7 +54,7 @@ pub struct WebviewWindowProps<'a> {
 ///
 ///
 pub fn WebviewWindow<'a>(cx: Context<'a>, props: &'a WebviewWindowProps) -> DomTree<'a> {
-    let dtcx = cx.use_consume_state::<RefCell<DesktopContext>>()?;
+    let dtcx = cx.consume_state::<RefCell<DesktopContext>>()?;
 
     cx.use_hook(
         |_| {

+ 36 - 57
packages/desktop/src/events.rs

@@ -1,16 +1,10 @@
 //! Convert a serialized event to an event Trigger
 //!
 
-use std::rc::Rc;
 use std::sync::Arc;
+use std::{any::Any, rc::Rc};
 
-use dioxus_core::{
-    events::{
-        on::{MouseEvent, MouseEventInner},
-        SyntheticEvent,
-    },
-    ElementId, EventPriority, ScopeId, UserEvent,
-};
+use dioxus_core::{events::on::MouseEvent, ElementId, EventPriority, ScopeId, UserEvent};
 
 #[derive(serde::Serialize, serde::Deserialize)]
 struct ImEvent {
@@ -43,85 +37,70 @@ pub fn trigger_from_serialized(val: serde_json::Value) -> UserEvent {
     }
 }
 
-fn make_synthetic_event(name: &str, val: serde_json::Value) -> SyntheticEvent {
+fn make_synthetic_event(name: &str, val: serde_json::Value) -> Box<dyn Any + Send> {
     use dioxus_core::events::on::*;
-    use dioxus_core::events::DioxusEvent;
 
     match name {
-        "copy" | "cut" | "paste" => SyntheticEvent::ClipboardEvent(ClipboardEvent(
-            DioxusEvent::new(ClipboardEventInner(), ()),
-        )),
+        "copy" | "cut" | "paste" => {
+            //
+            Box::new(ClipboardEvent {})
+        }
         "compositionend" | "compositionstart" | "compositionupdate" => {
-            SyntheticEvent::CompositionEvent(CompositionEvent(DioxusEvent::new(
-                serde_json::from_value(val).unwrap(),
-                (),
-            )))
+            Box::new(serde_json::from_value::<CompositionEvent>(val).unwrap())
+        }
+        "keydown" | "keypress" | "keyup" => {
+            Box::new(serde_json::from_value::<KeyboardEvent>(val).unwrap())
         }
-        "keydown" | "keypress" | "keyup" => SyntheticEvent::KeyboardEvent(KeyboardEvent(
-            DioxusEvent::new(serde_json::from_value(val).unwrap(), ()),
-        )),
         "focus" | "blur" => {
-            SyntheticEvent::FocusEvent(FocusEvent(DioxusEvent::new(FocusEventInner {}, ())))
+            //
+            Box::new(FocusEvent {})
         }
-        "change" => SyntheticEvent::GenericEvent(DioxusEvent::new((), ())),
 
         // todo: these handlers might get really slow if the input box gets large and allocation pressure is heavy
         // don't have a good solution with the serialized event problem
-        "input" | "invalid" | "reset" | "submit" => SyntheticEvent::FormEvent(FormEvent(
-            DioxusEvent::new(serde_json::from_value(val).unwrap(), ()),
-        )),
+        "change" | "input" | "invalid" | "reset" | "submit" => {
+            Box::new(serde_json::from_value::<FormEvent>(val).unwrap())
+        }
+
         "click" | "contextmenu" | "doubleclick" | "drag" | "dragend" | "dragenter" | "dragexit"
         | "dragleave" | "dragover" | "dragstart" | "drop" | "mousedown" | "mouseenter"
         | "mouseleave" | "mousemove" | "mouseout" | "mouseover" | "mouseup" => {
-            SyntheticEvent::MouseEvent(MouseEvent(DioxusEvent::new(
-                serde_json::from_value(val).unwrap(),
-                (),
-            )))
+            Box::new(serde_json::from_value::<MouseEvent>(val).unwrap())
         }
         "pointerdown" | "pointermove" | "pointerup" | "pointercancel" | "gotpointercapture"
         | "lostpointercapture" | "pointerenter" | "pointerleave" | "pointerover" | "pointerout" => {
-            SyntheticEvent::PointerEvent(PointerEvent(DioxusEvent::new(
-                serde_json::from_value(val).unwrap(),
-                (),
-            )))
+            Box::new(serde_json::from_value::<PointerEvent>(val).unwrap())
+        }
+        "select" => {
+            //
+            Box::new(serde_json::from_value::<SelectionEvent>(val).unwrap())
         }
-        "select" => SyntheticEvent::SelectionEvent(SelectionEvent(DioxusEvent::new(
-            SelectionEventInner {},
-            (),
-        ))),
 
-        "touchcancel" | "touchend" | "touchmove" | "touchstart" => SyntheticEvent::TouchEvent(
-            TouchEvent(DioxusEvent::new(serde_json::from_value(val).unwrap(), ())),
-        ),
+        "touchcancel" | "touchend" | "touchmove" | "touchstart" => {
+            Box::new(serde_json::from_value::<TouchEvent>(val).unwrap())
+        }
 
-        "scroll" => SyntheticEvent::GenericEvent(DioxusEvent::new((), ())),
+        "scroll" => Box::new(()),
 
-        "wheel" => SyntheticEvent::WheelEvent(WheelEvent(DioxusEvent::new(
-            serde_json::from_value(val).unwrap(),
-            (),
-        ))),
+        "wheel" => Box::new(serde_json::from_value::<WheelEvent>(val).unwrap()),
 
-        "animationstart" | "animationend" | "animationiteration" => SyntheticEvent::AnimationEvent(
-            AnimationEvent(DioxusEvent::new(serde_json::from_value(val).unwrap(), ())),
-        ),
+        "animationstart" | "animationend" | "animationiteration" => {
+            Box::new(serde_json::from_value::<AnimationEvent>(val).unwrap())
+        }
 
-        "transitionend" => SyntheticEvent::TransitionEvent(TransitionEvent(DioxusEvent::new(
-            serde_json::from_value(val).unwrap(),
-            (),
-        ))),
+        "transitionend" => Box::new(serde_json::from_value::<TransitionEvent>(val).unwrap()),
 
         "abort" | "canplay" | "canplaythrough" | "durationchange" | "emptied" | "encrypted"
         | "ended" | "error" | "loadeddata" | "loadedmetadata" | "loadstart" | "pause" | "play"
         | "playing" | "progress" | "ratechange" | "seeked" | "seeking" | "stalled" | "suspend"
         | "timeupdate" | "volumechange" | "waiting" => {
-            SyntheticEvent::MediaEvent(MediaEvent(DioxusEvent::new(MediaEventInner {}, ())))
+            //
+            Box::new(MediaEvent {})
         }
 
-        "toggle" => {
-            SyntheticEvent::ToggleEvent(ToggleEvent(DioxusEvent::new(ToggleEventInner {}, ())))
-        }
+        "toggle" => Box::new(ToggleEvent {}),
 
-        _ => SyntheticEvent::GenericEvent(DioxusEvent::new((), ())),
+        _ => Box::new(()),
     }
 }
 

+ 56 - 57
packages/desktop/src/index.js

@@ -50,6 +50,18 @@ class Interpreter {
     root.replaceWith(...els);
   }
 
+  InsertAfter(edit) {
+    let old = this.nodes[edit.root];
+    let new_nodes = this.stack.splice(this.stack.length - edit.n);
+    old.after(...new_nodes);
+  }
+
+  InsertBefore(edit) {
+    let old = this.nodes[edit.root];
+    let new_nodes = this.stack.splice(this.stack.length - edit.n);
+    old.before(...new_nodes);
+  }
+
   Remove(edit) {
     let node = this.nodes[edit.root];
     if (node !== undefined) {
@@ -78,74 +90,18 @@ class Interpreter {
 
   CreatePlaceholder(edit) {
     let el = document.createElement("pre");
-    // let el = document.createComment("vroot");
     this.stack.push(el);
     this.nodes[edit.root] = el;
   }
 
   RemoveEventListener(edit) { }
 
-  SetText(edit) {
-    this.top().textContent = edit.text;
-  }
-
-  SetAttribute(edit) {
-    const name = edit.field;
-    const value = edit.value;
-    const ns = edit.ns;
-    const node = this.top(this.stack);
-    if (ns == "style") {
-      node.style[name] = value;
-    } else if (ns !== undefined) {
-      node.setAttributeNS(ns, name, value);
-    } else {
-      node.setAttribute(name, value);
-    }
-    if (name === "value") {
-      node.value = value;
-    }
-    if (name === "checked") {
-      node.checked = true;
-    }
-    if (name === "selected") {
-      node.selected = true;
-    }
-  }
-  RemoveAttribute(edit) {
-    const name = edit.field;
-    const node = this.top(this.stack);
-    node.removeAttribute(name);
-
-    if (name === "value") {
-      node.value = null;
-    }
-    if (name === "checked") {
-      node.checked = false;
-    }
-    if (name === "selected") {
-      node.selected = false;
-    }
-  }
-
-  InsertAfter(edit) {
-    let old = this.nodes[edit.root];
-    let new_nodes = this.stack.splice(this.stack.length - edit.n);
-    // console.log("inserting nodes after", new_nodes, old);
-    old.after(...new_nodes);
-  }
-
-  InsertBefore(edit) {
-    let old = this.nodes[edit.root];
-    let new_nodes = this.stack.splice(this.stack.length - edit.n);
-    old.before(...new_nodes);
-  }
-
   NewEventListener(edit) {
     const event_name = edit.event_name;
     const mounted_node_id = edit.root;
     const scope = edit.scope;
 
-    const element = this.top();
+    const element = this.nodes[edit.root]
     element.setAttribute(`dioxus-event-${event_name}`, `${scope}.${mounted_node_id}`);
 
     if (this.listeners[event_name] === undefined) {
@@ -191,6 +147,49 @@ class Interpreter {
       });
     }
   }
+
+  SetText(edit) {
+    this.nodes[edit.root].textContent = edit.text;
+  }
+
+  SetAttribute(edit) {
+    const name = edit.field;
+    const value = edit.value;
+    const ns = edit.ns;
+    const node = this.nodes[edit.root]
+    if (ns == "style") {
+      node.style[name] = value;
+    } else if (ns !== undefined) {
+      node.setAttributeNS(ns, name, value);
+    } else {
+      node.setAttribute(name, value);
+    }
+    if (name === "value") {
+      node.value = value;
+    }
+    if (name === "checked") {
+      node.checked = true;
+    }
+    if (name === "selected") {
+      node.selected = true;
+    }
+  }
+  RemoveAttribute(edit) {
+    const name = edit.field;
+    const node = this.nodes[edit.root];
+    node.removeAttribute(name);
+
+    if (name === "value") {
+      node.value = null;
+    }
+    if (name === "checked") {
+      node.checked = false;
+    }
+    if (name === "selected") {
+      node.selected = false;
+    }
+  }
+
 }
 
 async function initialize() {

+ 3 - 0
packages/hooks/src/lib.rs

@@ -3,3 +3,6 @@ pub use usestate::{use_state, AsyncUseState, UseState};
 
 mod useref;
 pub use useref::*;
+
+mod use_shared_state;
+pub use use_shared_state::*;

+ 177 - 0
packages/hooks/src/use_shared_state.rs

@@ -0,0 +1,177 @@
+use dioxus_core::{prelude::Context, ScopeId};
+use std::{
+    cell::{Cell, Ref, RefCell, RefMut},
+    collections::HashSet,
+    rc::Rc,
+};
+
+type ProvidedState<T> = RefCell<ProvidedStateInner<T>>;
+
+// Tracks all the subscribers to a shared State
+pub(crate) struct ProvidedStateInner<T> {
+    value: Rc<RefCell<T>>,
+    notify_any: Rc<dyn Fn(ScopeId)>,
+    consumers: HashSet<ScopeId>,
+}
+
+impl<T> ProvidedStateInner<T> {
+    pub(crate) fn notify_consumers(&mut self) {
+        for consumer in self.consumers.iter() {
+            (self.notify_any)(*consumer);
+        }
+    }
+}
+
+/// This hook provides some relatively light ergonomics around shared state.
+///
+/// It is not a substitute for a proper state management system, but it is capable enough to provide use_state - type
+/// ergonimics in a pinch, with zero cost.
+///
+/// # Example
+///
+/// ## Provider
+///
+/// ```rust
+///
+///
+/// ```
+///
+/// ## Consumer
+///
+/// ```rust
+///
+///
+/// ```
+///
+/// # How it works
+///
+/// Any time a component calls `write`, every consumer of the state will be notified - excluding the provider.
+///
+/// Right now, there is not a distinction between read-only and write-only, so every consumer will be notified.
+///
+///
+///
+pub fn use_shared_state<'a, T: 'static>(cx: Context<'a>) -> Option<UseSharedState<'a, T>> {
+    cx.use_hook(
+        |_| {
+            let scope_id = cx.scope_id();
+            let root = cx.consume_state::<ProvidedState<T>>();
+
+            if let Some(root) = root.as_ref() {
+                root.borrow_mut().consumers.insert(scope_id);
+            }
+
+            let value = root.as_ref().map(|f| f.borrow().value.clone());
+            SharedStateInner {
+                root,
+                value,
+                scope_id,
+                needs_notification: Cell::new(false),
+            }
+        },
+        |f| {
+            //
+            f.needs_notification.set(false);
+            match (&f.value, &f.root) {
+                (Some(value), Some(root)) => Some(UseSharedState {
+                    cx,
+                    value,
+                    root,
+                    needs_notification: &f.needs_notification,
+                }),
+                _ => None,
+            }
+        },
+        |f| {
+            // we need to unsubscribe when our component is unounted
+            if let Some(root) = &f.root {
+                let mut root = root.borrow_mut();
+                root.consumers.remove(&f.scope_id);
+            }
+        },
+    )
+}
+
+struct SharedStateInner<T: 'static> {
+    root: Option<Rc<ProvidedState<T>>>,
+    value: Option<Rc<RefCell<T>>>,
+    scope_id: ScopeId,
+    needs_notification: Cell<bool>,
+}
+
+pub struct UseSharedState<'a, T: 'static> {
+    pub(crate) cx: Context<'a>,
+    pub(crate) value: &'a Rc<RefCell<T>>,
+    pub(crate) root: &'a Rc<RefCell<ProvidedStateInner<T>>>,
+    pub(crate) needs_notification: &'a Cell<bool>,
+}
+
+impl<'a, T: 'static> UseSharedState<'a, T> {
+    pub fn read(&self) -> Ref<'_, T> {
+        self.value.borrow()
+    }
+
+    pub fn notify_consumers(self) {
+        // if !self.needs_notification.get() {
+        self.root.borrow_mut().notify_consumers();
+        //     self.needs_notification.set(true);
+        // }
+    }
+
+    pub fn read_write(&self) -> (Ref<'_, T>, &Self) {
+        (self.read(), self)
+    }
+
+    /// Calling "write" will force the component to re-render
+    ///
+    ///
+    /// TODO: We prevent unncessary notifications only in the hook, but we should figure out some more global lock
+    pub fn write(&self) -> RefMut<'_, T> {
+        self.cx.needs_update();
+        self.notify_consumers();
+        self.value.borrow_mut()
+    }
+
+    /// Allows the ability to write the value without forcing a re-render
+    pub fn write_silent(&self) -> RefMut<'_, T> {
+        self.value.borrow_mut()
+    }
+}
+
+impl<T> Copy for UseSharedState<'_, T> {}
+impl<'a, T> Clone for UseSharedState<'a, T>
+where
+    T: 'static,
+{
+    fn clone(&self) -> Self {
+        UseSharedState {
+            cx: self.cx,
+            value: self.value,
+            root: self.root,
+            needs_notification: self.needs_notification,
+        }
+    }
+}
+
+/// Provide some state for components down the hierarchy to consume without having to drill props.
+///
+///
+///
+///
+///
+///
+///
+pub fn use_provide_state<'a, T: 'static>(cx: Context<'a>, f: impl FnOnce() -> T) {
+    cx.use_hook(
+        |_| {
+            let state: ProvidedState<T> = RefCell::new(ProvidedStateInner {
+                value: Rc::new(RefCell::new(f())),
+                notify_any: cx.schedule_update_any(),
+                consumers: HashSet::new(),
+            });
+            cx.provide_state(state)
+        },
+        |inner| {},
+        |_| {},
+    )
+}

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

@@ -2,7 +2,7 @@ use dioxus_core::prelude::Context;
 use std::{
     cell::{Cell, Ref, RefCell, RefMut},
     fmt::Display,
-    ops::{Deref, DerefMut, Not},
+    ops::Not,
     rc::Rc,
 };
 
@@ -121,8 +121,8 @@ impl<'a, T: 'static> UseState<'a, T> {
         self.inner.wip.borrow_mut()
     }
 
-    pub fn classic(self) -> (&'a T, &'a Rc<dyn Fn(T)>) {
-        todo!()
+    pub fn classic(self) -> (&'a T, Rc<dyn Fn(T)>) {
+        (&self.inner.current_val, self.setter())
     }
 
     pub fn setter(&self) -> Rc<dyn Fn(T)> {

+ 25 - 7
packages/html/src/lib.rs

@@ -479,6 +479,7 @@ pub trait GlobalAttributes {
 
         /// Specifies the treatment of content that overflows the element's box.
         overflow: "overflow",
+
         /// Specifies the treatment of content that overflows the element's box horizontally.
         overflow_x: "overflow-x",
 
@@ -518,6 +519,12 @@ pub trait GlobalAttributes {
         /// Specifies how an element is positioned.
         position: "position",
 
+        /// The pointer-events CSS property sets under what circumstances (if any) a particular graphic element can
+        /// become the target of pointer events.
+        ///
+        /// MDN: [`pointer_events`](https://developer.mozilla.org/en-US/docs/Web/CSS/pointer-events)
+        pointer_events: "pointer-events",
+
         /// Specifies quotation marks for embedded quotations.
         quotes: "quotes",
 
@@ -540,6 +547,7 @@ pub trait GlobalAttributes {
 
         /// Specifies the decoration added to text.
         text_decoration: "text-decoration",
+
         /// Specifies the color of the text_decoration_line.
         text_decoration_color: "text-decoration-color",
 
@@ -1527,19 +1535,19 @@ builder_constructors! {
         step: String,
         tabindex: usize,
 
-        // This has a manual implementation below
-        // r#type: InputType,
-
-        value: String,
         width: isize,
+
+        // Manual implementations below...
+        // r#type: InputType,
+        // value: String,
     };
 
     /// Build a
     /// [`<label>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/label)
     /// element.
     label {
-        r#for: Id,
         form: Id,
+        // r#for: Id,
     };
 
     /// Build a
@@ -1575,10 +1583,11 @@ builder_constructors! {
         disabled: Bool,
         label: String,
 
-        // defined below
-        // selected: Bool,
 
         value: String,
+
+        // defined below
+        // selected: Bool,
     };
 
     /// Build a
@@ -1694,6 +1703,10 @@ impl input {
     pub fn r#type<'a>(&self, cx: NodeFactory<'a>, val: Arguments) -> Attribute<'a> {
         cx.attr("type", val, None, false)
     }
+
+    pub fn value<'a>(&self, cx: NodeFactory<'a>, val: Arguments) -> Attribute<'a> {
+        cx.attr("value", val, None, true)
+    }
 }
 
 /*
@@ -1717,6 +1730,11 @@ impl textarea {
         cx.attr("value", val, None, true)
     }
 }
+impl label {
+    pub fn r#for<'a>(&self, cx: NodeFactory<'a>, val: Arguments) -> Attribute<'a> {
+        cx.attr("for", val, None, false)
+    }
+}
 
 pub trait SvgAttributes {
     aria_trait_methods! {

+ 1 - 1
packages/web/examples/async_web.rs

@@ -1,9 +1,9 @@
 //! Basic example that renders a simple VNode to the browser.
 use dioxus_core as dioxus;
 use dioxus_core::prelude::*;
+use dioxus_core_macro::*;
 use dioxus_hooks::*;
 use dioxus_html as dioxus_elements;
-use dioxus_core_macro::*;
 
 fn main() {
     console_error_panic_hook::set_once();

+ 147 - 152
packages/web/src/dom.rs

@@ -8,13 +8,13 @@
 //! - Partial delegation?>
 
 use dioxus_core::{
-    events::{DioxusEvent, KeyCode, SyntheticEvent, UserEvent},
+    events::{KeyCode, UserEvent},
     mutations::NodeRefMutation,
     scheduler::SchedulerMsg,
     DomEdit, ElementId, ScopeId,
 };
 use fxhash::FxHashMap;
-use std::{fmt::Debug, rc::Rc, sync::Arc};
+use std::{any::Any, fmt::Debug, rc::Rc, sync::Arc};
 use wasm_bindgen::{closure::Closure, JsCast};
 use web_sys::{
     Attr, CssStyleDeclaration, Document, Element, Event, HtmlElement, HtmlInputElement,
@@ -122,11 +122,18 @@ impl WebsysDom {
                     root: mounted_node_id,
                 } => self.new_event_listener(event_name, scope, mounted_node_id),
 
-                DomEdit::RemoveEventListener { event } => self.remove_event_listener(event),
+                DomEdit::RemoveEventListener { event, root } => {
+                    self.remove_event_listener(event, root)
+                }
 
-                DomEdit::SetText { text } => self.set_text(text),
-                DomEdit::SetAttribute { field, value, ns } => self.set_attribute(field, value, ns),
-                DomEdit::RemoveAttribute { name } => self.remove_attribute(name),
+                DomEdit::SetText { text, root } => self.set_text(text, root),
+                DomEdit::SetAttribute {
+                    field,
+                    value,
+                    ns,
+                    root,
+                } => self.set_attribute(field, value, ns, root),
+                DomEdit::RemoveAttribute { name, root } => self.remove_attribute(name, root),
 
                 DomEdit::InsertAfter { n, root } => self.insert_after(n, root),
                 DomEdit::InsertBefore { n, root } => self.insert_before(n, root),
@@ -211,7 +218,7 @@ impl WebsysDom {
 
     fn create_placeholder(&mut self, id: u64) {
         self.create_element("pre", None, id);
-        self.set_attribute("hidden", "", None);
+        // self.set_attribute("hidden", "", None);
     }
 
     fn create_text_node(&mut self, text: &str, id: u64) {
@@ -244,6 +251,9 @@ impl WebsysDom {
                 .unwrap(),
         };
 
+        let el2 = el.dyn_ref::<Element>().unwrap();
+        el2.set_attribute("dioxus-id", &format!("{}", id)).unwrap();
+
         self.stack.push(el.clone());
         self.nodes[(id as usize)] = Some(el);
     }
@@ -299,16 +309,17 @@ impl WebsysDom {
         }
     }
 
-    fn remove_event_listener(&mut self, event: &str) {
+    fn remove_event_listener(&mut self, event: &str, root: u64) {
         // todo!()
     }
 
-    fn set_text(&mut self, text: &str) {
-        self.stack.top().set_text_content(Some(text))
+    fn set_text(&mut self, text: &str, root: u64) {
+        let el = self.nodes[root as usize].as_ref().unwrap();
+        el.set_text_content(Some(text))
     }
 
-    fn set_attribute(&mut self, name: &str, value: &str, ns: Option<&str>) {
-        let node = self.stack.top();
+    fn set_attribute(&mut self, name: &str, value: &str, ns: Option<&str>, root: u64) {
+        let node = self.nodes[root as usize].as_ref().unwrap();
         if ns == Some("style") {
             if let Some(el) = node.dyn_ref::<Element>() {
                 let el = el.dyn_ref::<HtmlElement>().unwrap();
@@ -342,7 +353,11 @@ impl WebsysDom {
                 }
                 "checked" => {
                     if let Some(input) = node.dyn_ref::<HtmlInputElement>() {
-                        input.set_checked(true);
+                        match value {
+                            "true" => input.set_checked(true),
+                            "false" => input.set_checked(false),
+                            _ => fallback(),
+                        }
                     } else {
                         fallback();
                     }
@@ -359,8 +374,8 @@ impl WebsysDom {
         }
     }
 
-    fn remove_attribute(&mut self, name: &str) {
-        let node = self.stack.top();
+    fn remove_attribute(&mut self, name: &str, root: u64) {
+        let node = self.nodes[root as usize].as_ref().unwrap();
         if let Some(node) = node.dyn_ref::<web_sys::Element>() {
             node.remove_attribute(name).unwrap();
         }
@@ -400,18 +415,16 @@ impl WebsysDom {
     }
 
     fn insert_before(&mut self, n: u32, root: u64) {
-        let after = self.nodes[root as usize].as_ref().unwrap();
+        let anchor = self.nodes[root as usize].as_ref().unwrap();
 
         if n == 1 {
             let before = self.stack.pop();
 
-            after
+            anchor
                 .parent_node()
                 .unwrap()
-                .insert_before(&before, Some(&after))
+                .insert_before(&before, Some(&anchor))
                 .unwrap();
-
-            after.insert_before(&before, None).unwrap();
         } else {
             let arr: js_sys::Array = self
                 .stack
@@ -419,11 +432,11 @@ impl WebsysDom {
                 .drain((self.stack.list.len() - n as usize)..)
                 .collect();
 
-            if let Some(el) = after.dyn_ref::<Element>() {
+            if let Some(el) = anchor.dyn_ref::<Element>() {
                 el.before_with_node(&arr).unwrap();
-            } else if let Some(el) = after.dyn_ref::<web_sys::CharacterData>() {
+            } else if let Some(el) = anchor.dyn_ref::<web_sys::CharacterData>() {
                 el.before_with_node(&arr).unwrap();
-            } else if let Some(el) = after.dyn_ref::<web_sys::DocumentType>() {
+            } else if let Some(el) = anchor.dyn_ref::<web_sys::DocumentType>() {
                 el.before_with_node(&arr).unwrap();
             }
         }
@@ -470,56 +483,61 @@ unsafe impl Sync for DioxusWebsysEvent {}
 
 // todo: some of these events are being casted to the wrong event type.
 // We need tests that simulate clicks/etc and make sure every event type works.
-fn virtual_event_from_websys_event(event: web_sys::Event) -> SyntheticEvent {
+fn virtual_event_from_websys_event(event: web_sys::Event) -> Box<dyn Any + Send> {
     use crate::events::*;
     use dioxus_core::events::on::*;
     match event.type_().as_str() {
-        "copy" | "cut" | "paste" => SyntheticEvent::ClipboardEvent(ClipboardEvent(
-            DioxusEvent::new(ClipboardEventInner(), DioxusWebsysEvent(event)),
-        )),
+        "copy" | "cut" | "paste" => Box::new(ClipboardEvent {}),
         "compositionend" | "compositionstart" | "compositionupdate" => {
             let evt: &web_sys::CompositionEvent = event.dyn_ref().unwrap();
-            SyntheticEvent::CompositionEvent(CompositionEvent(DioxusEvent::new(
-                CompositionEventInner {
-                    data: evt.data().unwrap_or_default(),
-                },
-                DioxusWebsysEvent(event),
-            )))
+            Box::new(CompositionEvent {
+                data: evt.data().unwrap_or_default(),
+            })
         }
         "keydown" | "keypress" | "keyup" => {
             let evt: &web_sys::KeyboardEvent = event.dyn_ref().unwrap();
-            SyntheticEvent::KeyboardEvent(KeyboardEvent(DioxusEvent::new(
-                KeyboardEventInner {
-                    alt_key: evt.alt_key(),
-                    char_code: evt.char_code(),
-                    key: evt.key(),
-                    key_code: KeyCode::from_raw_code(evt.key_code() as u8),
-                    ctrl_key: evt.ctrl_key(),
-                    locale: "not implemented".to_string(),
-                    location: evt.location() as usize,
-                    meta_key: evt.meta_key(),
-                    repeat: evt.repeat(),
-                    shift_key: evt.shift_key(),
-                    which: evt.which() as usize,
-                },
-                DioxusWebsysEvent(event),
-            )))
+            Box::new(KeyboardEvent {
+                alt_key: evt.alt_key(),
+                char_code: evt.char_code(),
+                key: evt.key(),
+                key_code: KeyCode::from_raw_code(evt.key_code() as u8),
+                ctrl_key: evt.ctrl_key(),
+                locale: "not implemented".to_string(),
+                location: evt.location() as usize,
+                meta_key: evt.meta_key(),
+                repeat: evt.repeat(),
+                shift_key: evt.shift_key(),
+                which: evt.which() as usize,
+            })
         }
-        "focus" | "blur" => SyntheticEvent::FocusEvent(FocusEvent(DioxusEvent::new(
-            FocusEventInner {},
-            DioxusWebsysEvent(event),
-        ))),
-        "change" => SyntheticEvent::GenericEvent(DioxusEvent::new((), DioxusWebsysEvent(event))),
+        "focus" | "blur" => {
+            //
+            Box::new(FocusEvent {})
+        }
+        // "change" => SyntheticEvent::GenericEvent(DioxusEvent::new((), DioxusWebsysEvent(event))),
 
         // todo: these handlers might get really slow if the input box gets large and allocation pressure is heavy
         // don't have a good solution with the serialized event problem
-        "input" | "invalid" | "reset" | "submit" => {
+        "change" | "input" | "invalid" | "reset" | "submit" => {
             let evt: &web_sys::Event = event.dyn_ref().unwrap();
 
             let target: web_sys::EventTarget = evt.target().unwrap();
             let value: String = (&target)
                 .dyn_ref()
-                .map(|input: &web_sys::HtmlInputElement| input.value())
+                .map(|input: &web_sys::HtmlInputElement| {
+                    // todo: special case more input types
+                    match input.type_().as_str() {
+                        "checkbox" => {
+                           match input.checked() {
+                                true => "true".to_string(),
+                                false => "false".to_string(),
+                            }
+                        },
+                        _ => {
+                            input.value()
+                        }
+                    }
+                })
                 .or_else(|| {
                     target
                         .dyn_ref()
@@ -539,135 +557,112 @@ fn virtual_event_from_websys_event(event: web_sys::Event) -> SyntheticEvent {
                 })
                 .expect("only an InputElement or TextAreaElement or an element with contenteditable=true can have an oninput event listener");
 
-            SyntheticEvent::FormEvent(FormEvent(DioxusEvent::new(
-                FormEventInner { value },
-                DioxusWebsysEvent(event),
-            )))
+            Box::new(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.dyn_ref().unwrap();
-            SyntheticEvent::MouseEvent(MouseEvent(DioxusEvent::new(
-                MouseEventInner {
-                    alt_key: evt.alt_key(),
-                    button: evt.button(),
-                    buttons: evt.buttons(),
-                    client_x: evt.client_x(),
-                    client_y: evt.client_y(),
-                    ctrl_key: evt.ctrl_key(),
-                    meta_key: evt.meta_key(),
-                    screen_x: evt.screen_x(),
-                    screen_y: evt.screen_y(),
-                    shift_key: evt.shift_key(),
-                    page_x: evt.page_x(),
-                    page_y: evt.page_y(),
-                },
-                DioxusWebsysEvent(event),
-            )))
+            Box::new(MouseEvent {
+                alt_key: evt.alt_key(),
+                button: evt.button(),
+                buttons: evt.buttons(),
+                client_x: evt.client_x(),
+                client_y: evt.client_y(),
+                ctrl_key: evt.ctrl_key(),
+                meta_key: evt.meta_key(),
+                screen_x: evt.screen_x(),
+                screen_y: evt.screen_y(),
+                shift_key: evt.shift_key(),
+                page_x: evt.page_x(),
+                page_y: evt.page_y(),
+            })
         }
         "pointerdown" | "pointermove" | "pointerup" | "pointercancel" | "gotpointercapture"
         | "lostpointercapture" | "pointerenter" | "pointerleave" | "pointerover" | "pointerout" => {
             let evt: &web_sys::PointerEvent = event.dyn_ref().unwrap();
-            SyntheticEvent::PointerEvent(PointerEvent(DioxusEvent::new(
-                PointerEventInner {
-                    alt_key: evt.alt_key(),
-                    button: evt.button(),
-                    buttons: evt.buttons(),
-                    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(),
-                    pointer_id: evt.pointer_id(),
-                    width: evt.width(),
-                    height: evt.height(),
-                    pressure: evt.pressure(),
-                    tangential_pressure: evt.tangential_pressure(),
-                    tilt_x: evt.tilt_x(),
-                    tilt_y: evt.tilt_y(),
-                    twist: evt.twist(),
-                    pointer_type: evt.pointer_type(),
-                    is_primary: evt.is_primary(),
-                    // get_modifier_state: evt.get_modifier_state(),
-                },
-                DioxusWebsysEvent(event),
-            )))
+            Box::new(PointerEvent {
+                alt_key: evt.alt_key(),
+                button: evt.button(),
+                buttons: evt.buttons(),
+                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(),
+                pointer_id: evt.pointer_id(),
+                width: evt.width(),
+                height: evt.height(),
+                pressure: evt.pressure(),
+                tangential_pressure: evt.tangential_pressure(),
+                tilt_x: evt.tilt_x(),
+                tilt_y: evt.tilt_y(),
+                twist: evt.twist(),
+                pointer_type: evt.pointer_type(),
+                is_primary: evt.is_primary(),
+                // get_modifier_state: evt.get_modifier_state(),
+            })
         }
-        "select" => SyntheticEvent::SelectionEvent(SelectionEvent(DioxusEvent::new(
-            SelectionEventInner {},
-            DioxusWebsysEvent(event),
-        ))),
+        "select" => Box::new(SelectionEvent {}),
 
         "touchcancel" | "touchend" | "touchmove" | "touchstart" => {
             let evt: &web_sys::TouchEvent = event.dyn_ref().unwrap();
-            SyntheticEvent::TouchEvent(TouchEvent(DioxusEvent::new(
-                TouchEventInner {
-                    alt_key: evt.alt_key(),
-                    ctrl_key: evt.ctrl_key(),
-                    meta_key: evt.meta_key(),
-                    shift_key: evt.shift_key(),
-                },
-                DioxusWebsysEvent(event),
-            )))
+            Box::new(TouchEvent {
+                alt_key: evt.alt_key(),
+                ctrl_key: evt.ctrl_key(),
+                meta_key: evt.meta_key(),
+                shift_key: evt.shift_key(),
+            })
         }
 
-        "scroll" => SyntheticEvent::GenericEvent(DioxusEvent::new((), DioxusWebsysEvent(event))),
+        "scroll" => Box::new(()),
 
         "wheel" => {
             let evt: &web_sys::WheelEvent = event.dyn_ref().unwrap();
-            SyntheticEvent::WheelEvent(WheelEvent(DioxusEvent::new(
-                WheelEventInner {
-                    delta_x: evt.delta_x(),
-                    delta_y: evt.delta_y(),
-                    delta_z: evt.delta_z(),
-                    delta_mode: evt.delta_mode(),
-                },
-                DioxusWebsysEvent(event),
-            )))
+            Box::new(WheelEvent {
+                delta_x: evt.delta_x(),
+                delta_y: evt.delta_y(),
+                delta_z: evt.delta_z(),
+                delta_mode: evt.delta_mode(),
+            })
         }
 
         "animationstart" | "animationend" | "animationiteration" => {
             let evt: &web_sys::AnimationEvent = event.dyn_ref().unwrap();
-            SyntheticEvent::AnimationEvent(AnimationEvent(DioxusEvent::new(
-                AnimationEventInner {
-                    elapsed_time: evt.elapsed_time(),
-                    animation_name: evt.animation_name(),
-                    pseudo_element: evt.pseudo_element(),
-                },
-                DioxusWebsysEvent(event),
-            )))
+            Box::new(AnimationEvent {
+                elapsed_time: evt.elapsed_time(),
+                animation_name: evt.animation_name(),
+                pseudo_element: evt.pseudo_element(),
+            })
         }
 
         "transitionend" => {
             let evt: &web_sys::TransitionEvent = event.dyn_ref().unwrap();
-            SyntheticEvent::TransitionEvent(TransitionEvent(DioxusEvent::new(
-                TransitionEventInner {
-                    elapsed_time: evt.elapsed_time(),
-                    property_name: evt.property_name(),
-                    pseudo_element: evt.pseudo_element(),
-                },
-                DioxusWebsysEvent(event),
-            )))
+            Box::new(TransitionEvent {
+                elapsed_time: evt.elapsed_time(),
+                property_name: evt.property_name(),
+                pseudo_element: evt.pseudo_element(),
+            })
         }
 
         "abort" | "canplay" | "canplaythrough" | "durationchange" | "emptied" | "encrypted"
         | "ended" | "error" | "loadeddata" | "loadedmetadata" | "loadstart" | "pause" | "play"
         | "playing" | "progress" | "ratechange" | "seeked" | "seeking" | "stalled" | "suspend"
-        | "timeupdate" | "volumechange" | "waiting" => SyntheticEvent::MediaEvent(MediaEvent(
-            DioxusEvent::new(MediaEventInner {}, DioxusWebsysEvent(event)),
-        )),
+        | "timeupdate" | "volumechange" | "waiting" => {
+            //
+            Box::new(MediaEvent {})
+        }
 
-        "toggle" => SyntheticEvent::ToggleEvent(ToggleEvent(DioxusEvent::new(
-            ToggleEventInner {},
-            DioxusWebsysEvent(event),
-        ))),
+        "toggle" => {
+            //
+            Box::new(ToggleEvent {})
+        }
 
-        _ => SyntheticEvent::GenericEvent(DioxusEvent::new((), DioxusWebsysEvent(event))),
+        _ => Box::new(()),
     }
 }
 

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

@@ -176,7 +176,7 @@ pub async fn run_with_props<T: 'static + Send>(root: FC<T>, root_props: T, cfg:
         work_loop.wait_for_raf().await;
 
         for mut edit in mutations {
-            log::debug!("edits are {:#?}", edit);
+            // log::debug!("edits are {:#?}", edit);
             // actually apply our changes during the animation frame
             websys_dom.process_edits(&mut edit.edits);
         }