Pārlūkot izejas kodu

wip: overhaul event system

Jonathan Kelley 3 gadi atpakaļ
vecāks
revīzija
7a03c1d

+ 1 - 0
Cargo.toml

@@ -85,6 +85,7 @@ members = [
     "packages/ssr",
     "packages/ssr",
     "packages/desktop",
     "packages/desktop",
     "packages/mobile",
     "packages/mobile",
+    "packages/webview-client"
 ]
 ]
 
 
 
 

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

@@ -1,3 +1,5 @@
+use dioxus::events::on::MouseEvent;
+use dioxus::events::DioxusEvent;
 use dioxus_core as dioxus;
 use dioxus_core as dioxus;
 use dioxus_core::prelude::*;
 use dioxus_core::prelude::*;
 use dioxus_core_macro::*;
 use dioxus_core_macro::*;
@@ -37,6 +39,9 @@ struct RowProps {
     label: Label,
     label: Label,
 }
 }
 fn Row<'a>(cx: Context<'a>, props: &'a RowProps) -> DomTree<'a> {
 fn Row<'a>(cx: Context<'a>, props: &'a RowProps) -> DomTree<'a> {
+    let handler = move |evt: MouseEvent| {
+        let g = evt.button;
+    };
     cx.render(rsx! {
     cx.render(rsx! {
         tr {
         tr {
             td { class:"col-md-1", "{props.row_id}" }
             td { class:"col-md-1", "{props.row_id}" }
@@ -44,7 +49,7 @@ fn Row<'a>(cx: Context<'a>, props: &'a RowProps) -> DomTree<'a> {
                 a { class: "lbl", "{props.label}" }
                 a { class: "lbl", "{props.label}" }
             }
             }
             td { class: "col-md-1"
             td { class: "col-md-1"
-                a { class: "remove", onclick: move |_| {/* remove */}
+                a { class: "remove", onclick: {handler}
                     span { class: "glyphicon glyphicon-remove remove" aria_hidden: "true" }
                     span { class: "glyphicon glyphicon-remove remove" aria_hidden: "true" }
                 }
                 }
             }
             }

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

@@ -0,0 +1,1023 @@
+//! 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
+            }
+        }
+    }
+}

+ 456 - 439
packages/core/src/events.rs

@@ -1,8 +1,8 @@
-//! This module provides a set of common events for all Dioxus apps to target, regardless of host platform.
-//! -------------------------------------------------------------------------------------------------------
+//! An event system that's less confusing than Traits + RC;
+//! This should hopefully make it easier to port to other platforms.
 //!
 //!
-//! 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.
+//! Unfortunately, it is less efficient than the original, but hopefully it's negligible.
+
 use crate::{
 use crate::{
     innerlude::Listener,
     innerlude::Listener,
     innerlude::{ElementId, NodeFactory, ScopeId},
     innerlude::{ElementId, NodeFactory, ScopeId},
@@ -34,6 +34,7 @@ pub struct UserEvent {
     pub event: SyntheticEvent,
     pub event: SyntheticEvent,
 }
 }
 
 
+#[derive(Debug)]
 pub enum SyntheticEvent {
 pub enum SyntheticEvent {
     AnimationEvent(on::AnimationEvent),
     AnimationEvent(on::AnimationEvent),
     ClipboardEvent(on::ClipboardEvent),
     ClipboardEvent(on::ClipboardEvent),
@@ -41,7 +42,7 @@ pub enum SyntheticEvent {
     FocusEvent(on::FocusEvent),
     FocusEvent(on::FocusEvent),
     FormEvent(on::FormEvent),
     FormEvent(on::FormEvent),
     KeyboardEvent(on::KeyboardEvent),
     KeyboardEvent(on::KeyboardEvent),
-    GenericEvent(on::GenericEvent),
+    GenericEvent(DioxusEvent<()>),
     TouchEvent(on::TouchEvent),
     TouchEvent(on::TouchEvent),
     ToggleEvent(on::ToggleEvent),
     ToggleEvent(on::ToggleEvent),
     MediaEvent(on::MediaEvent),
     MediaEvent(on::MediaEvent),
@@ -51,31 +52,6 @@ pub enum SyntheticEvent {
     TransitionEvent(on::TransitionEvent),
     TransitionEvent(on::TransitionEvent),
     PointerEvent(on::PointerEvent),
     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.
 /// Priority of Event Triggers.
 ///
 ///
@@ -129,82 +105,101 @@ pub enum EventPriority {
     Low = 0,
     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),
+#[derive(Debug)]
+pub struct DioxusEvent<T: Send> {
+    inner: T,
+    raw: Box<dyn Any + Send>,
+}
 
 
-        // Focus
-        "focus" | "blur" => (true, Low),
+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 }
+    }
 
 
-        // Form
-        "change" | "input" | "invalid" | "reset" | "submit" => (true, Medium),
+    /// 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()
+    }
 
 
-        // Mouse
-        "click" | "contextmenu" | "doubleclick" | "drag" | "dragend" | "dragenter" | "dragexit"
-        | "dragleave" | "dragover" | "dragstart" | "drop" | "mousedown" | "mouseenter"
-        | "mouseleave" | "mouseout" | "mouseover" | "mouseup" => (true, High),
+    /// Returns whether or not a specific event is a bubbling event
+    pub fn bubbles(&self) -> bool {
+        todo!()
+    }
+    /// Sets or returns whether the event should propagate up the hierarchy or not
+    pub fn cancel_bubble(&self) {
+        todo!()
+    }
+    /// Returns whether or not an event can have its default action prevented
+    pub fn cancelable(&self) -> bool {
+        todo!()
+    }
+    /// Returns whether the event is composed or not
+    pub fn composed(&self) -> bool {
+        todo!()
+    }
 
 
-        "mousemove" => (false, Medium),
+    // 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
+    // pub fn composed_path(&self) -> String {
+    //     todo!()
+    // }
 
 
-        // Pointer
-        "pointerdown" | "pointermove" | "pointerup" | "pointercancel" | "gotpointercapture"
-        | "lostpointercapture" | "pointerenter" | "pointerleave" | "pointerover" | "pointerout" => {
-            (true, Medium)
-        }
+    /// Returns the element whose event listeners triggered the event
+    pub fn current_target(&self) {
+        todo!()
+    }
+    /// Returns whether or not the preventDefault method was called for the event
+    pub fn default_prevented(&self) -> bool {
+        todo!()
+    }
+    /// Returns which phase of the event flow is currently being evaluated
+    pub fn event_phase(&self) -> u16 {
+        todo!()
+    }
 
 
-        // Selection
-        "select" | "touchcancel" | "touchend" => (true, Medium),
+    /// Returns whether or not an event is trusted
+    pub fn is_trusted(&self) -> bool {
+        todo!()
+    }
 
 
-        // Touch
-        "touchmove" | "touchstart" => (true, Medium),
+    /// Cancels the event if it is cancelable, meaning that the default action that belongs to the event will
+    pub fn prevent_default(&self) {
+        todo!()
+    }
 
 
-        // Wheel
-        "scroll" | "wheel" => (false, Medium),
+    /// Prevents other listeners of the same event from being called
+    pub fn stop_immediate_propagation(&self) {
+        todo!()
+    }
 
 
-        // 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),
+    /// Prevents further propagation of an event during event flow
+    pub fn stop_propagation(&self) {
+        todo!()
+    }
 
 
-        // Animation
-        "animationstart" | "animationend" | "animationiteration" => (true, Medium),
+    /// Returns the element that triggered the event
+    pub fn target(&self) -> Option<Box<dyn Any>> {
+        todo!()
+    }
 
 
-        // Transition
-        "transitionend" => (true, Medium),
+    /// Returns the time (in milliseconds relative to the epoch) at which the event was created
+    pub fn time_stamp(&self) -> f64 {
+        todo!()
+    }
+}
 
 
-        // Toggle
-        "toggle" => (true, Medium),
+impl<T: Send + Sync> std::ops::Deref for DioxusEvent<T> {
+    type Target = T;
 
 
-        _ => (true, Low),
+    fn deref(&self) -> &Self::Target {
+        &self.inner
     }
     }
 }
 }
 
 
-pub use on::{
-    AnimationEvent, ClipboardEvent, CompositionEvent, FocusEvent, FormEvent, GenericEvent, KeyCode,
-    KeyboardEvent, MediaEvent, MouseEvent, PointerEvent, SelectionEvent, ToggleEvent, TouchEvent,
-    TransitionEvent, WheelEvent,
-};
-
 pub mod on {
 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::*;
     use super::*;
-
     macro_rules! event_directory {
     macro_rules! event_directory {
         ( $(
         ( $(
             $( #[$attr:meta] )*
             $( #[$attr:meta] )*
@@ -217,13 +212,14 @@ pub mod on {
         )* ) => {
         )* ) => {
             $(
             $(
                 $(#[$attr])*
                 $(#[$attr])*
-                pub struct $wrapper(pub Arc<dyn $eventdata>);
+                #[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)
                 // 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
                 // 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
                 // Either we ask for this to be changed in Rust-analyzer or manually impkement the trait
                 impl Deref for $wrapper {
                 impl Deref for $wrapper {
-                    type Target = Arc<dyn $eventdata>;
+                    type Target = DioxusEvent<$eventdata>;
                     fn deref(&self) -> &Self::Target {
                     fn deref(&self) -> &Self::Target {
                         &self.0
                         &self.0
                     }
                     }
@@ -599,57 +595,20 @@ pub mod on {
         ];
         ];
     }
     }
 
 
-    pub struct GenericEvent(pub Arc<dyn GenericEventInner>);
-
-    pub trait GenericEventInner {
-        /// 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 {
+    #[derive(Debug)]
+    pub struct ClipboardEventInner(
         // DOMDataTransfer clipboardData
         // DOMDataTransfer clipboardData
-    }
+    );
 
 
-    pub trait CompositionEventInner {
-        fn data(&self) -> String;
+    #[derive(Debug)]
+    pub struct CompositionEventInner {
+        pub data: String,
     }
     }
 
 
-    pub trait KeyboardEventInner {
-        fn alt_key(&self) -> bool;
-
-        fn char_code(&self) -> u32;
+    #[derive(Debug)]
+    pub struct KeyboardEventInner {
+        pub alt_key: bool,
+        pub char_code: u32,
 
 
         /// Identify which "key" was entered.
         /// Identify which "key" was entered.
         ///
         ///
@@ -669,8 +628,8 @@ pub mod on {
         ///      _ => {}
         ///      _ => {}
         /// }
         /// }
         /// ```
         /// ```
-        ///
-        fn key(&self) -> String;
+        ///    
+        pub key: String,
 
 
         /// Get the key code as an enum Variant.
         /// Get the key code as an enum Variant.
         ///
         ///
@@ -689,335 +648,393 @@ pub mod on {
         ///     _ => {}
         ///     _ => {}
         /// }
         /// }
         /// ```
         /// ```
-        ///
-        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 key_code: KeyCode,
+        pub ctrl_key: bool,
+        pub locale: String,
+        pub location: usize,
+        pub meta_key: bool,
+        pub repeat: bool,
+        pub shift_key: bool,
+        pub which: usize,
+        // get_modifier_state: bool,
     }
     }
 
 
-    pub trait FocusEventInner {
-        /* DOMEventInnerTarget relatedTarget */
-    }
+    #[derive(Debug)]
+    pub struct FocusEventInner {/* DOMEventInner:  Send + SyncTarget relatedTarget */}
 
 
-    pub trait FormEventInner {
-        fn value(&self) -> String;
+    #[derive(Debug)]
+    pub struct FormEventInner {
+        /* DOMEventInner:  Send + SyncTarget relatedTarget */
+        pub value: String,
     }
     }
 
 
-    pub trait MouseEventInner {
-        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;
+    #[derive(Debug)]
+    pub struct MouseEventInner {
+        pub alt_key: bool,
+        pub button: i16,
+        pub buttons: u16,
+        pub client_x: i32,
+        pub client_y: i32,
+        pub ctrl_key: bool,
+        pub meta_key: bool,
+        pub page_x: i32,
+        pub page_y: i32,
+        pub screen_x: i32,
+        pub screen_y: i32,
+        pub shift_key: bool,
+        // fn get_modifier_state(&self, key_code: &str) -> bool;
     }
     }
 
 
-    pub trait PointerEventInner {
+    #[derive(Debug)]
+    pub struct PointerEventInner {
         // Mouse only
         // 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 alt_key: bool,
+        pub button: i16,
+        pub buttons: u16,
+        pub client_x: i32,
+        pub client_y: i32,
+        pub ctrl_key: bool,
+        pub meta_key: bool,
+        pub page_x: i32,
+        pub page_y: i32,
+        pub screen_x: i32,
+        pub screen_y: i32,
+        pub shift_key: bool,
+        pub pointer_id: i32,
+        pub width: i32,
+        pub height: i32,
+        pub pressure: f32,
+        pub tangential_pressure: f32,
+        pub tilt_x: i32,
+        pub tilt_y: i32,
+        pub twist: i32,
+        pub pointer_type: String,
+        pub is_primary: bool,
+        // pub get_modifier_state: bool,
     }
     }
 
 
-    pub trait SelectionEventInner {}
+    #[derive(Debug)]
+    pub struct SelectionEventInner {}
 
 
-    pub trait TouchEventInner {
-        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;
+    #[derive(Debug)]
+    pub struct TouchEventInner {
+        pub alt_key: bool,
+        pub ctrl_key: bool,
+        pub meta_key: bool,
+        pub shift_key: bool,
+        // get_modifier_state: bool,
         // changedTouches: DOMTouchList,
         // changedTouches: DOMTouchList,
         // targetTouches: DOMTouchList,
         // targetTouches: DOMTouchList,
         // touches: DOMTouchList,
         // touches: DOMTouchList,
     }
     }
 
 
-    pub trait UIEventInner {
-        // DOMAbstractView view
-        fn detail(&self) -> i32;
+    #[derive(Debug)]
+    pub struct WheelEventInner {
+        pub delta_mode: u32,
+        pub delta_x: f64,
+        pub delta_y: f64,
+        pub delta_z: f64,
     }
     }
 
 
-    pub trait WheelEventInner {
-        fn delta_mode(&self) -> u32;
-        fn delta_x(&self) -> f64;
-        fn delta_y(&self) -> f64;
-        fn delta_z(&self) -> f64;
-    }
+    #[derive(Debug)]
+    pub struct MediaEventInner {}
 
 
-    pub trait MediaEventInner {}
-
-    pub trait ImageEventInner {
+    #[derive(Debug)]
+    pub struct ImageEventInner {
         //     load error
         //     load error
+        pub load_error: bool,
     }
     }
 
 
-    pub trait AnimationEventInner {
-        fn animation_name(&self) -> String;
-        fn pseudo_element(&self) -> String;
-        fn elapsed_time(&self) -> f32;
+    #[derive(Debug)]
+    pub struct AnimationEventInner {
+        pub animation_name: String,
+        pub pseudo_element: String,
+        pub elapsed_time: f32,
     }
     }
 
 
-    pub trait TransitionEventInner {
-        fn property_name(&self) -> String;
-        fn pseudo_element(&self) -> String;
-        fn elapsed_time(&self) -> f32;
+    #[derive(Debug)]
+    pub struct TransitionEventInner {
+        pub property_name: String,
+        pub pseudo_element: String,
+        pub elapsed_time: f32,
     }
     }
 
 
-    pub trait ToggleEventInner {}
-
-    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,
+    #[derive(Debug)]
+    pub struct ToggleEventInner {}
+}
+
+#[derive(Clone, Copy, Debug)]
+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,
         }
         }
+    }
 
 
-        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
+    }
+}
 
 
-            // get the raw code
-            pub fn raw_code(&self) -> u32 {
-                *self as u32
-            }
+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),
     }
     }
 }
 }

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

@@ -19,6 +19,7 @@ pub mod context;
 pub mod diff;
 pub mod diff;
 pub mod diff_stack;
 pub mod diff_stack;
 pub mod events;
 pub mod events;
+// pub mod events2;
 pub mod heuristics;
 pub mod heuristics;
 pub mod hooklist;
 pub mod hooklist;
 pub mod hooks;
 pub mod hooks;
@@ -61,8 +62,8 @@ pub(crate) mod innerlude {
 
 
 pub use crate::innerlude::{
 pub use crate::innerlude::{
     Context, DioxusElement, DomEdit, DomTree, ElementId, EventPriority, LazyNodes, MountType,
     Context, DioxusElement, DomEdit, DomTree, ElementId, EventPriority, LazyNodes, MountType,
-    Mutations, NodeFactory, Properties, ScopeId, SuspendedContext, SyntheticEvent, TaskHandle,
-    TestDom, ThreadsafeVirtualDom, UserEvent, VNode, VirtualDom, FC,
+    Mutations, NodeFactory, Properties, SchedulerMsg, ScopeId, SuspendedContext, SyntheticEvent,
+    TaskHandle, TestDom, ThreadsafeVirtualDom, UserEvent, VNode, VirtualDom, FC,
 };
 };
 
 
 pub mod prelude {
 pub mod prelude {
@@ -78,4 +79,5 @@ pub mod exports {
     //! Important dependencies that are used by the rest of the library
     //! Important dependencies that are used by the rest of the library
     // the foundation of this library
     // the foundation of this library
     pub use bumpalo;
     pub use bumpalo;
+    pub use futures_channel;
 }
 }

+ 0 - 2
packages/core/src/mutations.rs

@@ -185,7 +185,6 @@ pub enum DomEdit<'bump> {
         root: u64,
         root: u64,
     },
     },
 
 
-    RemoveAllChildren,
     CreateTextNode {
     CreateTextNode {
         text: &'bump str,
         text: &'bump str,
         id: u64,
         id: u64,
@@ -232,7 +231,6 @@ impl DomEdit<'_> {
             DomEdit::AppendChildren { .. } => id == "AppendChildren",
             DomEdit::AppendChildren { .. } => id == "AppendChildren",
             DomEdit::ReplaceWith { .. } => id == "ReplaceWith",
             DomEdit::ReplaceWith { .. } => id == "ReplaceWith",
             DomEdit::Remove { .. } => id == "Remove",
             DomEdit::Remove { .. } => id == "Remove",
-            DomEdit::RemoveAllChildren => id == "RemoveAllChildren",
             DomEdit::CreateTextNode { .. } => id == "CreateTextNode",
             DomEdit::CreateTextNode { .. } => id == "CreateTextNode",
             DomEdit::CreateElement { .. } => id == "CreateElement",
             DomEdit::CreateElement { .. } => id == "CreateElement",
             DomEdit::CreateElementNs { .. } => id == "CreateElementNs",
             DomEdit::CreateElementNs { .. } => id == "CreateElementNs",

+ 0 - 10
packages/core/src/resources.rs

@@ -43,16 +43,6 @@ impl ResourcePool {
         inner.get_mut(idx.0)
         inner.get_mut(idx.0)
     }
     }
 
 
-    // return a bumpframe with a lifetime attached to the arena borrow
-    // this is useful for merging lifetimes
-    pub fn with_scope_vnode<'b>(
-        &self,
-        _id: ScopeId,
-        _f: impl FnOnce(&mut Scope) -> &VNode<'b>,
-    ) -> Option<&VNode<'b>> {
-        todo!()
-    }
-
     pub fn try_remove(&self, id: ScopeId) -> Option<Scope> {
     pub fn try_remove(&self, id: ScopeId) -> Option<Scope> {
         let inner = unsafe { &mut *self.components.get() };
         let inner = unsafe { &mut *self.components.get() };
         Some(inner.remove(id.0))
         Some(inner.remove(id.0))

+ 15 - 8
packages/core/src/scheduler.rs

@@ -106,7 +106,8 @@ pub enum SchedulerMsg {
 }
 }
 
 
 pub enum TaskMsg {
 pub enum TaskMsg {
-    SubmitTask(FiberTask, u64),
+    // SubmitTask(FiberTask, u64),
+    // SubmitTask(FiberTask, u64),
     ToggleTask(u64),
     ToggleTask(u64),
     PauseTask(u64),
     PauseTask(u64),
     ResumeTask(u64),
     ResumeTask(u64),
@@ -163,7 +164,10 @@ pub(crate) struct Scheduler {
 }
 }
 
 
 impl Scheduler {
 impl Scheduler {
-    pub(crate) fn new() -> Self {
+    pub(crate) fn new(
+        sender: UnboundedSender<SchedulerMsg>,
+        receiver: UnboundedReceiver<SchedulerMsg>,
+    ) -> Self {
         /*
         /*
         Preallocate 2000 elements and 100 scopes to avoid dynamic allocation.
         Preallocate 2000 elements and 100 scopes to avoid dynamic allocation.
         Perhaps this should be configurable from some external config?
         Perhaps this should be configurable from some external config?
@@ -173,7 +177,6 @@ impl Scheduler {
 
 
         let heuristics = HeuristicsEngine::new();
         let heuristics = HeuristicsEngine::new();
 
 
-        let (sender, receiver) = futures_channel::mpsc::unbounded::<SchedulerMsg>();
         let task_counter = Rc::new(Cell::new(0));
         let task_counter = Rc::new(Cell::new(0));
 
 
         let channel = EventChannel {
         let channel = EventChannel {
@@ -183,15 +186,19 @@ impl Scheduler {
                 let sender = sender.clone();
                 let sender = sender.clone();
                 Rc::new(move |id| sender.unbounded_send(SchedulerMsg::Immediate(id)).unwrap())
                 Rc::new(move |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
             submit_task: {
             submit_task: {
                 Rc::new(move |fiber_task| {
                 Rc::new(move |fiber_task| {
                     let task_id = task_counter.get();
                     let task_id = task_counter.get();
                     task_counter.set(task_id + 1);
                     task_counter.set(task_id + 1);
-                    sender
-                        .unbounded_send(SchedulerMsg::Task(TaskMsg::SubmitTask(
-                            fiber_task, task_id,
-                        )))
-                        .unwrap();
+
+                    todo!();
+                    // sender
+                    //     .unbounded_send(SchedulerMsg::Task(TaskMsg::SubmitTask(
+                    //         fiber_task, task_id,
+                    //     )))
+                    //     .unwrap();
                     TaskHandle {
                     TaskHandle {
                         our_id: task_id,
                         our_id: task_id,
                         sender: sender.clone(),
                         sender: sender.clone(),

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

@@ -12,7 +12,8 @@ pub struct TestDom {
 impl TestDom {
 impl TestDom {
     pub fn new() -> TestDom {
     pub fn new() -> TestDom {
         let bump = Bump::new();
         let bump = Bump::new();
-        let scheduler = Scheduler::new();
+        let (sender, receiver) = futures_channel::mpsc::unbounded::<SchedulerMsg>();
+        let scheduler = Scheduler::new(sender, receiver);
         TestDom { bump, scheduler }
         TestDom { bump, scheduler }
     }
     }
 
 

+ 19 - 4
packages/core/src/threadsafe.rs

@@ -1,5 +1,12 @@
 //! A threadsafe wrapper for the VirtualDom
 //! A threadsafe wrapper for the VirtualDom
-
+//!
+//! This is an experimental module, and must be explicitly opted-into.
+//!
+//! It's not guaranteed that this module produces safe results, so use at your own peril.
+//!
+//! The only real "right" answer to a Send VirtualDom is by ensuring all hook data is Send
+//!
+//!
 use std::sync::{Arc, Mutex, MutexGuard};
 use std::sync::{Arc, Mutex, MutexGuard};
 
 
 use crate::VirtualDom;
 use crate::VirtualDom;
@@ -18,9 +25,17 @@ use crate::VirtualDom;
 /// directly. Even then, it's not possible to access any hook data. This means that non-Send types are only "in play"
 /// directly. Even then, it's not possible to access any hook data. This means that non-Send types are only "in play"
 /// while the VirtualDom is locked with a non-Send marker.
 /// while the VirtualDom is locked with a non-Send marker.
 ///
 ///
-/// Note that calling "wait for work" on the regular VirtualDom is inherently non-Send. If there are async tasks that
-/// need to be awaited, they must be done thread-local since we don't place any requirements on user tasks. This can be
-/// done with the function "spawn_local" in either tokio or async_std.
+/// Calling "wait for work" on the ThreadsafeVirtualDom does indeed work, because this method only accesses `Send` types.
+/// Otherwise, the VirtualDom must be unlocked on the current thread to modify any data.
+///
+/// Dioxus does have the concept of local tasks and non-local tasks.
+///
+/// For the ThreadsafeVirtualDom, non-Send tasks are not ran - and will error out during a Debug build if one is submitted.
+///
+///
+///
+/// When Tasks are submitted to a thread-local executor,
+///
 pub struct ThreadsafeVirtualDom {
 pub struct ThreadsafeVirtualDom {
     inner: Arc<Mutex<VirtualDom>>,
     inner: Arc<Mutex<VirtualDom>>,
 }
 }

+ 58 - 52
packages/core/src/virtual_dom.rs

@@ -19,8 +19,10 @@
 //! This module includes just the barebones for a complete VirtualDOM API.
 //! This module includes just the barebones for a complete VirtualDOM API.
 //! Additional functionality is defined in the respective files.
 //! Additional functionality is defined in the respective files.
 
 
+use futures_channel::mpsc::{UnboundedReceiver, UnboundedSender};
+
 use crate::innerlude::*;
 use crate::innerlude::*;
-use std::{any::Any, rc::Rc, sync::Arc};
+use std::{any::Any, rc::Rc};
 
 
 /// An integrated virtual node system that progresses events and diffs UI trees.
 /// An integrated virtual node system that progresses events and diffs UI trees.
 ///
 ///
@@ -121,6 +123,20 @@ impl VirtualDom {
     /// let mutations = dom.rebuild();
     /// let mutations = dom.rebuild();
     /// ```
     /// ```
     pub fn new_with_props<P: 'static + Send>(root: FC<P>, root_props: P) -> Self {
     pub fn new_with_props<P: 'static + Send>(root: FC<P>, root_props: P) -> Self {
+        let (sender, receiver) = futures_channel::mpsc::unbounded::<SchedulerMsg>();
+        Self::new_with_props_and_scheduler(root, root_props, sender, receiver)
+    }
+
+    /// Launch the VirtualDom, but provide your own channel for receiving and sending messages into the scheduler.
+    ///
+    /// This is useful when the VirtualDom must be driven from outside a thread and it doesn't make sense to wait for the
+    /// VirtualDom to be created just to retrive its channel receiver.
+    pub fn new_with_props_and_scheduler<P: 'static + Send>(
+        root: FC<P>,
+        root_props: P,
+        sender: UnboundedSender<SchedulerMsg>,
+        receiver: UnboundedReceiver<SchedulerMsg>,
+    ) -> Self {
         let root_fc = Box::new(root);
         let root_fc = Box::new(root);
 
 
         let root_props: Rc<dyn Any + Send> = Rc::new(root_props);
         let root_props: Rc<dyn Any + Send> = Rc::new(root_props);
@@ -132,7 +148,7 @@ impl VirtualDom {
             std::mem::transmute(root(Context { scope }, props))
             std::mem::transmute(root(Context { scope }, props))
         });
         });
 
 
-        let scheduler = Scheduler::new();
+        let scheduler = Scheduler::new(sender, receiver);
 
 
         let base_scope = scheduler.pool.insert_scope_with_key(|myidx| {
         let base_scope = scheduler.pool.insert_scope_with_key(|myidx| {
             Scope::new(
             Scope::new(
@@ -343,47 +359,46 @@ impl VirtualDom {
     /// Waits for the scheduler to have work
     /// Waits for the scheduler to have work
     /// This lets us poll async tasks during idle periods without blocking the main thread.
     /// This lets us poll async tasks during idle periods without blocking the main thread.
     pub async fn wait_for_work(&mut self) {
     pub async fn wait_for_work(&mut self) {
-        todo!("making vdom send right now");
-        // 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::Immediate(im) => {
-        //                 self.scheduler.dirty_scopes.insert(im);
-        //             }
-        //             SchedulerMsg::UiEvent(evt) => {
-        //                 self.scheduler.ui_events.push_back(evt);
-        //             }
-        //         }
-        //     },
-        // }
-
-        // 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);
-        //         }
-        //     }
-        // }
+        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::Immediate(im) => {
+                        self.scheduler.dirty_scopes.insert(im);
+                    }
+                    SchedulerMsg::UiEvent(evt) => {
+                        self.scheduler.ui_events.push_back(evt);
+                    }
+                }
+            },
+        }
+
+        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);
+                }
+            }
+        }
     }
     }
 }
 }
 
 
@@ -407,14 +422,5 @@ impl std::fmt::Display for VirtualDom {
     }
     }
 }
 }
 
 
-/*
-Send safety...
-
-The VirtualDom can only be "send" if the internals exposed to user code are also "send".
-
-IE it's okay to move an Rc from one thread to another thread as long as it's only used internally
-
-*/
-
 // we never actually use the contents of this root caller
 // we never actually use the contents of this root caller
 struct RootCaller(Rc<dyn for<'b> Fn(&'b Scope) -> DomTree<'b> + 'static>);
 struct RootCaller(Rc<dyn for<'b> Fn(&'b Scope) -> DomTree<'b> + 'static>);

+ 0 - 4
packages/core/tests/eventsystem.rs

@@ -16,8 +16,4 @@ async fn event_queue_works() {
 
 
     let mut dom = VirtualDom::new(App);
     let mut dom = VirtualDom::new(App);
     let edits = dom.rebuild();
     let edits = dom.rebuild();
-
-    async_std::task::spawn_local(async move {
-        // let mutations = dom.run_unbounded().await;
-    });
 }
 }

+ 2 - 1
packages/desktop/.vscode/settings.json

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

+ 4 - 3
packages/desktop/Cargo.toml

@@ -19,15 +19,16 @@ thiserror = "1.0.23"
 log = "0.4.13"
 log = "0.4.13"
 fern = { version = "0.6.0", features = ["colored"] }
 fern = { version = "0.6.0", features = ["colored"] }
 html-escape = "0.2.9"
 html-escape = "0.2.9"
-wry = "0.11.0"
+# wry = { version = "0.12.2", git = "https://github.com/jkelleyrtp/wry.git", branch = "jk/fnmut_rpc" }
+wry = "0.12.2"
 tokio = { version = "1.12.0", features = ["full"] }
 tokio = { version = "1.12.0", features = ["full"] }
+futures-channel = "0.3.16"
 
 
 
 
 [dev-dependencies]
 [dev-dependencies]
 dioxus-html = { path = "../html" }
 dioxus-html = { path = "../html" }
-tide = "0.15.0"
-tide-websockets = "0.3.0"
 dioxus-core-macro = { path = "../core-macro" }
 dioxus-core-macro = { path = "../core-macro" }
+dioxus-hooks = { path = "../hooks" }
 # thiserror = "1.0.23"
 # thiserror = "1.0.23"
 # log = "0.4.13"
 # log = "0.4.13"
 # fern = { version = "0.6.0", features = ["colored"] }
 # fern = { version = "0.6.0", features = ["colored"] }

+ 17 - 19
packages/desktop/README.md

@@ -6,26 +6,19 @@ Dioxus-webview is an attempt at making a simpler "Tauri" where creating desktop
 
 
 ```rust
 ```rust
 // main.rs
 // main.rs
-#[async_std::main]
-async fn main() {
-   dioxus_desktop::new(|cx, props|{
-       let (count, set_count) = use_state(cx, || 0);
-       cx.render(html! {
-            <div>
-                <h1> "Dioxus Desktop Demo" </h1>
-                <p> "Count is {count}"</p>
-                <button onclick=|_| set_count(count + 1) >
-                    "Click to increment"
-                </button>
-            </div>
-       })
-   })
-   .configure_webview(|view| {
-      // custom webview config options
-   })
-   .launch()
-   .await;
+fn main() {
+    dioxus_desktop::new(App, |c| c)
+    .launch()
+    .await;
 }
 }
+static App: FC<()> = |cx, props|{
+    let (count, set_count) = use_state(cx, || 0);
+    rsx!(cx, div {
+        h1 { "Dioxus Desktop Demo" }
+        p { "Count is {count}"}
+        button { onclick: move |_| count += 1}
+    })
+};
 ```
 ```
 
 
 and then to create a native .app:
 and then to create a native .app:
@@ -45,3 +38,8 @@ By bridging the native process, desktop apps can access full multithreading powe
 Dioxus-desktop is a pure liveview application where all of the state and event handlers are proxied through the liveview and into the native process. For pure server-based liveview, this would normally be too slow (in both render performance and latency), but because the VDom is local, desktop apps are just as fast as Electron.
 Dioxus-desktop is a pure liveview application where all of the state and event handlers are proxied through the liveview and into the native process. For pure server-based liveview, this would normally be too slow (in both render performance and latency), but because the VDom is local, desktop apps are just as fast as Electron.
 
 
 Dioxus-desktop leverages dioxus-liveview under the hood, but with convenience wrappers around setting up the VDom bridge, proxying events, and serving the initial WebSys-Renderer. The backend is served by Tide, so an async runtime _is_ needed - we recommend async-std in Tokio mode.
 Dioxus-desktop leverages dioxus-liveview under the hood, but with convenience wrappers around setting up the VDom bridge, proxying events, and serving the initial WebSys-Renderer. The backend is served by Tide, so an async runtime _is_ needed - we recommend async-std in Tokio mode.
+
+
+## Async Runtime
+
+

+ 33 - 0
packages/desktop/examples/core.rs

@@ -0,0 +1,33 @@
+use dioxus_core::prelude::*;
+use dioxus_core_macro::*;
+use dioxus_html as dioxus_elements;
+
+fn main() {
+    let (window_loop, tasks) = dioxus_desktop::start(App, |c| c);
+
+    std::thread::spawn(move || {
+        //
+        let runtime = tokio::runtime::Builder::new_multi_thread()
+            .enable_all()
+            .build()
+            .unwrap();
+
+        runtime.block_on(async move {
+            let mut vir = VirtualDom::new_with_props(root, props);
+            let channel = vir.get_event_sender();
+            loop {
+                vir.wait_for_work().await;
+                let edits = vir.run_with_deadline(|| false);
+                let edit_string = serde_json::to_string(&edits[0].edits).unwrap();
+                event_tx.send(edit_string).unwrap();
+            }
+        })
+    });
+
+    window_loop.run();
+}
+
+static App: FC<()> = |cx| {
+    //
+    cx.render(rsx!(div {}))
+};

+ 111 - 0
packages/desktop/examples/crm.rs

@@ -0,0 +1,111 @@
+use dioxus_core as dioxus;
+use dioxus_core::prelude::*;
+use dioxus_core_macro::*;
+use dioxus_hooks::*;
+
+use dioxus_html as dioxus_elements;
+
+fn main() {
+    dioxus_desktop::set_up_logging(true);
+    dioxus_desktop::launch(App, |c| c).unwrap();
+}
+
+enum Scene {
+    ClientsList,
+    NewClientForm,
+    Settings,
+}
+
+#[derive(Clone, Debug, Default)]
+pub struct Client {
+    pub first_name: String,
+    pub last_name: String,
+    pub description: String,
+}
+
+static App: FC<()> = |cx, _| {
+    let scene = use_state(cx, || Scene::ClientsList);
+    let clients = use_ref(cx, || vec![] as Vec<Client>);
+
+    let firstname = use_state(cx, || String::new());
+    let lastname = use_state(cx, || String::new());
+    let description = use_state(cx, || String::new());
+
+    let scene = match *scene {
+        Scene::ClientsList => {
+            rsx!(cx, div { class: "crm"
+                h2 { "List of clients" margin_bottom: "10px" }
+                div { class: "clients" margin_left: "10px"
+                    {clients.read().iter().map(|client| rsx!(
+                        div { class: "client" style: "margin-bottom: 50px"
+                            p { "First Name: {client.first_name}" }
+                            p { "Last Name: {client.last_name}" }
+                            p {"Description: {client.description}"}
+                        })
+                    )}
+                }
+                button { class: "pure-button pure-button-primary" onclick: move |_| scene.set(Scene::NewClientForm), "Add New" }
+                button { class: "pure-button" onclick: move |_| scene.set(Scene::Settings), "Settings" }
+            })
+        }
+        Scene::NewClientForm => {
+            let add_new = move |_| {
+                clients.write().push(Client {
+                    description: (*description).clone(),
+                    first_name: (*firstname).clone(),
+                    last_name: (*lastname).clone(),
+                });
+                description.set(String::new());
+                firstname.set(String::new());
+                lastname.set(String::new());
+            };
+            rsx!(cx, div { class: "crm"
+                h2 {"Add new client" margin_bottom: "10px" }
+                form { class: "pure-form"
+                    input { class: "new-client firstname" placeholder: "First name" value: "{firstname}"
+                        oninput: move |evt| firstname.set(evt.value())
+                    }
+                    input { class: "new-client lastname" placeholder: "Last name" value: "{lastname}"
+                        oninput: move |evt| lastname.set(evt.value())
+                    }
+                    textarea { class: "new-client description" placeholder: "Description" value: "{description}"
+                        oninput: move |evt| description.set(evt.value())
+                    }
+                }
+                button { class: "pure-button pure-button-primary", onclick: {add_new}, "Add New" }
+                button { class: "pure-button", onclick: move |_| scene.set(Scene::ClientsList), "Go Back" }
+            })
+        }
+        Scene::Settings => {
+            rsx!(cx, div {
+                h2 { "Settings" margin_bottom: "10px" }
+                button {
+                    background: "rgb(202, 60, 60)"
+                    class: "pure-button pure-button-primary"
+                    onclick: move |_| {
+                        clients.write().clear();
+                        scene.set(Scene::ClientsList);
+                    },
+                    "Remove all clients"
+                }
+                button {
+                    class: "pure-button pure-button-primary"
+                    onclick: move |_| scene.set(Scene::ClientsList),
+                    "Go Back"
+                }
+            })
+        }
+    };
+
+    rsx!(cx, body {
+        link {
+            rel: "stylesheet"
+            href: "https://unpkg.com/purecss@2.0.6/build/pure-min.css"
+            integrity: "sha384-Uu6IeWbM+gzNVXJcM9XV3SohHtmWE+3VGi496jvgX1jyvDTXfdK+rfZc8C1Aehk5"
+            crossorigin: "anonymous"
+        }
+        margin_left: "35%"
+        h1 {"Dioxus CRM Example"}
+        {scene}
+    })
+};

+ 2 - 8
packages/desktop/examples/demo.rs

@@ -5,20 +5,14 @@ use dioxus_core_macro::*;
 use dioxus_html as dioxus_elements;
 use dioxus_html as dioxus_elements;
 
 
 fn main() {
 fn main() {
-    std::thread::spawn(|| {
-        let mut vdom = VirtualDom::new(App);
-        let f = async_std::task::block_on(vdom.wait_for_work());
-    });
-    let a = 10;
-    // async_std::task::spawn_blocking(|| async move {
-    // });
+    dioxus_desktop::launch(App, |c| c).unwrap();
 }
 }
 
 
 static App: FC<()> = |cx, props| {
 static App: FC<()> = |cx, props| {
-    //
     cx.render(rsx!(
     cx.render(rsx!(
         div {
         div {
             "hello world!"
             "hello world!"
         }
         }
+        {(0..10).map(|f| rsx!( div {"abc {f}"}))}
     ))
     ))
 };
 };

+ 11 - 0
packages/desktop/examples/tauri.rs

@@ -0,0 +1,11 @@
+fn main() {
+    tauri::AppBuilder::default().setup(move |app, name| {
+        //
+        let window = app.get_window();
+
+        let window = app.get_window();
+        tauri::spawn(|| async move {
+            //
+        });
+    });
+}

+ 10 - 4
packages/desktop/src/cfg.rs

@@ -4,30 +4,36 @@ use dioxus_core::DomEdit;
 use wry::{
 use wry::{
     application::{
     application::{
         error::OsError,
         error::OsError,
-        event_loop::EventLoopWindowTarget,
+        event_loop::{EventLoop, EventLoopWindowTarget},
         menu::MenuBar,
         menu::MenuBar,
         window::{Fullscreen, Icon, Window, WindowBuilder},
         window::{Fullscreen, Icon, Window, WindowBuilder},
     },
     },
-    webview::{RpcRequest, RpcResponse},
+    webview::{RpcRequest, RpcResponse, WebView},
 };
 };
 
 
 pub struct DesktopConfig<'a> {
 pub struct DesktopConfig<'a> {
     pub window: WindowBuilder,
     pub window: WindowBuilder,
-    pub(crate) manual_edits: Option<DomEdit<'a>>,
+    pub(crate) manual_edits: Option<Vec<DomEdit<'a>>>,
     pub(crate) pre_rendered: Option<String>,
     pub(crate) pre_rendered: Option<String>,
+    pub(crate) event_handler: Option<Box<dyn Fn(&mut EventLoop<()>, &mut WebView)>>,
 }
 }
 
 
-impl DesktopConfig<'_> {
+impl<'a> DesktopConfig<'a> {
     /// Initializes a new `WindowBuilder` with default values.
     /// Initializes a new `WindowBuilder` with default values.
     #[inline]
     #[inline]
     pub fn new() -> Self {
     pub fn new() -> Self {
         Self {
         Self {
+            event_handler: None,
             window: Default::default(),
             window: Default::default(),
             pre_rendered: None,
             pre_rendered: None,
             manual_edits: None,
             manual_edits: None,
         }
         }
     }
     }
 
 
+    pub fn with_edits(&mut self, edits: Vec<DomEdit<'a>>) {
+        self.manual_edits = Some(edits);
+    }
+
     pub fn with_prerendered(&mut self, content: String) -> &mut Self {
     pub fn with_prerendered(&mut self, content: String) -> &mut Self {
         self.pre_rendered = Some(content);
         self.pre_rendered = Some(content);
         self
         self

+ 86 - 55
packages/desktop/src/events.rs

@@ -22,69 +22,100 @@ pub fn trigger_from_serialized(val: serde_json::Value) -> UserEvent {
     let mut data: Vec<ImEvent> = serde_json::from_value(val).unwrap();
     let mut data: Vec<ImEvent> = serde_json::from_value(val).unwrap();
     let data = data.drain(..).next().unwrap();
     let data = data.drain(..).next().unwrap();
 
 
-    let event = SyntheticEvent::MouseEvent(MouseEvent(Arc::new(WebviewMouseEvent)));
     let scope = ScopeId(data.scope as usize);
     let scope = ScopeId(data.scope as usize);
     let mounted_dom_id = Some(ElementId(data.mounted_dom_id as usize));
     let mounted_dom_id = Some(ElementId(data.mounted_dom_id as usize));
+
     UserEvent {
     UserEvent {
-        name: todo!(),
+        name: "click",
         event,
         event,
         scope,
         scope,
         mounted_dom_id,
         mounted_dom_id,
     }
     }
 }
 }
 
 
-#[derive(Debug)]
-struct WebviewMouseEvent;
-impl MouseEventInner for WebviewMouseEvent {
-    fn alt_key(&self) -> bool {
-        todo!()
-    }
-
-    fn button(&self) -> i16 {
-        todo!()
-    }
-
-    fn buttons(&self) -> u16 {
-        todo!()
-    }
-
-    fn client_x(&self) -> i32 {
-        todo!()
-    }
-
-    fn client_y(&self) -> i32 {
-        todo!()
-    }
-
-    fn ctrl_key(&self) -> bool {
-        todo!()
-    }
-
-    fn meta_key(&self) -> bool {
-        todo!()
-    }
-
-    fn page_x(&self) -> i32 {
-        todo!()
-    }
-
-    fn page_y(&self) -> i32 {
-        todo!()
-    }
-
-    fn screen_x(&self) -> i32 {
-        todo!()
-    }
-
-    fn screen_y(&self) -> i32 {
-        todo!()
-    }
-
-    fn shift_key(&self) -> bool {
-        todo!()
-    }
-
-    fn get_modifier_state(&self, key_code: &str) -> bool {
-        todo!()
+fn event_name_from_typ(typ: &str) -> &'static str {
+    match typ {
+        "copy" => "copy",
+        "cut" => "cut",
+        "paste" => "paste",
+        "compositionend" => "compositionend",
+        "compositionstart" => "compositionstart",
+        "compositionupdate" => "compositionupdate",
+        "keydown" => "keydown",
+        "keypress" => "keypress",
+        "keyup" => "keyup",
+        "focus" => "focus",
+        "blur" => "blur",
+        "change" => "change",
+        "input" => "input",
+        "invalid" => "invalid",
+        "reset" => "reset",
+        "submit" => "submit",
+        "click" => "click",
+        "contextmenu" => "contextmenu",
+        "doubleclick" => "doubleclick",
+        "drag" => "drag",
+        "dragend" => "dragend",
+        "dragenter" => "dragenter",
+        "dragexit" => "dragexit",
+        "dragleave" => "dragleave",
+        "dragover" => "dragover",
+        "dragstart" => "dragstart",
+        "drop" => "drop",
+        "mousedown" => "mousedown",
+        "mouseenter" => "mouseenter",
+        "mouseleave" => "mouseleave",
+        "mousemove" => "mousemove",
+        "mouseout" => "mouseout",
+        "mouseover" => "mouseover",
+        "mouseup" => "mouseup",
+        "pointerdown" => "pointerdown",
+        "pointermove" => "pointermove",
+        "pointerup" => "pointerup",
+        "pointercancel" => "pointercancel",
+        "gotpointercapture" => "gotpointercapture",
+        "lostpointercapture" => "lostpointercapture",
+        "pointerenter" => "pointerenter",
+        "pointerleave" => "pointerleave",
+        "pointerover" => "pointerover",
+        "pointerout" => "pointerout",
+        "select" => "select",
+        "touchcancel" => "touchcancel",
+        "touchend" => "touchend",
+        "touchmove" => "touchmove",
+        "touchstart" => "touchstart",
+        "scroll" => "scroll",
+        "wheel" => "wheel",
+        "animationstart" => "animationstart",
+        "animationend" => "animationend",
+        "animationiteration" => "animationiteration",
+        "transitionend" => "transitionend",
+        "abort" => "abort",
+        "canplay" => "canplay",
+        "canplaythrough" => "canplaythrough",
+        "durationchange" => "durationchange",
+        "emptied" => "emptied",
+        "encrypted" => "encrypted",
+        "ended" => "ended",
+        "error" => "error",
+        "loadeddata" => "loadeddata",
+        "loadedmetadata" => "loadedmetadata",
+        "loadstart" => "loadstart",
+        "pause" => "pause",
+        "play" => "play",
+        "playing" => "playing",
+        "progress" => "progress",
+        "ratechange" => "ratechange",
+        "seeked" => "seeked",
+        "seeking" => "seeking",
+        "stalled" => "stalled",
+        "suspend" => "suspend",
+        "timeupdate" => "timeupdate",
+        "volumechange" => "volumechange",
+        "waiting" => "waiting",
+        "toggle" => "toggle",
+        _ => {
+            panic!("unsupported event type")
+        }
     }
     }
 }
 }

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

@@ -9,212 +9,7 @@
     <div id="_dioxusroot">
     <div id="_dioxusroot">
     </div>
     </div>
 </body>
 </body>
-<script>
-    class Interpreter {
-        constructor(root) {
-            this.root = root;
-            this.stack = [root];
-            this.listeners = {
-                "onclick": {}
-            };
-            this.lastNodeWasText = false;
-            this.nodes = [root, root, root, root];
-        }
-
-        top() {
-            return this.stack[this.stack.length - 1];
-        }
-
-        pop() {
-            return this.stack.pop();
-        }
-
-        PushRoot(edit) {
-            const id = edit.id;
-            const node = this.nodes[id];
-            console.log("pushing root ", node, "with id", id);
-            this.stack.push(node);
-        }
-
-        PopRoot(edit) {
-            this.stack.pop();
-        }
-
-        AppendChildren(edit) {
-            let root = this.stack[this.stack.length - (edit.many + 1)];
-            for (let i = 0; i < edit.many; i++) {
-                console.log("popping ", i, edit.many);
-                let node = this.pop();
-                root.appendChild(node);
-            }
-        }
-
-        ReplaceWith(edit) {
-
-            let root = this.stack[this.stack.length - (edit.many + 1)];
-            let els = [];
-
-            for (let i = 0; i < edit.many; i++) {
-                els.push(this.pop());
-            }
-
-            root.replaceWith(...els);
-        }
-
-        Remove(edit) {
-            const node = this.stack.pop();
-            node.remove();
-        }
-
-        RemoveAllChildren(edit) {}
-
-        CreateTextNode(edit) {
-            const node = document.createTextNode(edit.text);
-            this.nodes[edit.id] = node;
-            this.stack.push(node);
-        }
-
-        CreateElement(edit) {
-            const tagName = edit.tag;
-            const el = document.createElement(tagName);
-            this.nodes[edit.id] = el;
-            console.log(`creating element: `, edit);
-            this.stack.push(el);
-        }
-
-        CreateElementNs(edit) {
-            const tagName = edit.tag;
-            console.log(`creating namespaced element: `, edit);
-            this.stack.push(document.createElementNS(edit.ns, edit.tag));
-        }
-
-        CreatePlaceholder(edit) {
-            const a = `this.stack.push(document.createElement(" pre"))`;
-            this.stack.push(document.createComment("vroot"));
-        }
-
-        NewEventListener(edit) {
-            const element_id = edit.element_id;
-            const event_name = edit.event_name;
-            const mounted_node_id = edit.mounted_node_id;
-            const scope = edit.scope;
-
-            const element = this.top();
-            element.setAttribute(`dioxus-event-${event_name}`, `${scope}.${mounted_node_id}`);
-
-            console.log("listener map is", this.listeners);
-            if (this.listeners[event_name] === undefined) {
-                console.log("adding listener!");
-                this.listeners[event_name] = "bla";
-                this.root.addEventListener(event_name, (event) => {
-                    const target = event.target;
-                    const type = event.type;
-                    const val = target.getAttribute(`dioxus-event-${event_name}`);
-                    const fields = val.split(".");
-                    const scope_id = parseInt(fields[0]);
-                    const real_id = parseInt(fields[1]);
-
-                    console.log(`parsed event with scope_id ${scope_id} and real_id ${real_id}`);
-
-                    rpc.call('user_event', {
-                        event: event_name,
-                        scope: scope_id,
-                        mounted_dom_id: real_id,
-                    }).then((reply) => {
-                        console.log(reply);
-                        this.stack.push(this.root);
-
-                        let edits = reply.edits;
-
-                        for (let x = 0; x < edits.length; x++) {
-                            let edit = edits[x];
-                            console.log(edit);
-
-                            let f = this[edit.type];
-                            f.call(this, edit);
-                        }
-
-                        console.log("initiated");
-                    }).catch((err) => {
-                        console.log("failed to initiate", err);
-                    });
-                });
-            }
-        }
-
-        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;
-            }
-        }
-    }
-
-
-
-
-    async function initialize() {
-        const reply = await rpc.call('initiate');
-        let root = window.document.getElementById("_dioxusroot");
-        const interpreter = new Interpreter(root);
-        console.log(reply);
-
-        let pre_rendered = reply.pre_rendered;
-        if (pre_rendered !== undefined) {
-            root.innerHTML = pre_rendered;
-        }
-
-        const edits = reply.edits;
-
-        for (let x = 0; x < edits.length; x++) {
-            let edit = edits[x];
-            console.log(edit);
-
-            let f = interpreter[edit.type];
-            f.call(interpreter, edit);
-        }
-
-        console.log("stack completed: ", interpreter.stack);
-    }
-    console.log("initializing...");
-    initialize();
+<script type="text/javascript" src="/index.js">
 </script>
 </script>
 
 
 </html>
 </html>

+ 216 - 0
packages/desktop/src/index.js

@@ -0,0 +1,216 @@
+
+class Interpreter {
+  constructor(root) {
+    this.root = root;
+    this.stack = [root];
+    this.listeners = {
+      "onclick": {}
+    };
+    this.lastNodeWasText = false;
+    this.nodes = [root, root, root, root];
+  }
+
+  top() {
+    return this.stack[this.stack.length - 1];
+  }
+
+  pop() {
+    return this.stack.pop();
+  }
+
+  PushRoot(edit) {
+    const id = edit.id;
+    const node = this.nodes[id];
+    console.log("pushing root ", node, "with id", id);
+    this.stack.push(node);
+  }
+
+  PopRoot(_edit) {
+    this.stack.pop();
+  }
+
+  AppendChildren(edit) {
+    let root = this.stack[this.stack.length - (1 + edit.many)];
+
+    let to_add = this.stack.splice(this.stack.length - edit.many);
+
+    for (let i = 0; i < edit.many; i++) {
+      root.appendChild(to_add[i]);
+    }
+  }
+
+  ReplaceWith(edit) {
+    console.log(edit);
+    let root = this.nodes[edit.root];
+    let els = this.stack.splice(this.stack.length - edit.m);
+
+    console.log(root);
+    console.log(els);
+
+
+    root.replaceWith(...els);
+  }
+
+  Remove(edit) {
+    let node = this.nodes[edit.element_id];
+    node.remove();
+  }
+
+  CreateTextNode(edit) {
+    const node = document.createTextNode(edit.text);
+    this.nodes[edit.id] = node;
+    this.stack.push(node);
+  }
+
+  CreateElement(edit) {
+    const tagName = edit.tag;
+    const el = document.createElement(tagName);
+    this.nodes[edit.id] = el;
+    this.stack.push(el);
+  }
+
+  CreateElementNs(edit) {
+    let el = document.createElementNS(edit.ns, edit.tag);
+    this.stack.push(el);
+    this.nodes[edit.id] = el;
+  }
+
+  CreatePlaceholder(edit) {
+    let el = document.createElement("pre");
+    // let el = document.createComment("vroot");
+    this.stack.push(el);
+    this.nodes[edit.id] = 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.element_id];
+    let new_nodes = this.stack.splice(edit.many);
+    old.after(...new_nodes);
+  }
+
+  InsertBefore(edit) {
+    let old = this.nodes[edit.element_id];
+    let new_nodes = this.stack.splice(edit.many);
+    old.before(...new_nodes);
+  }
+
+  NewEventListener(edit) {
+    const event_name = edit.event_name;
+    const mounted_node_id = edit.mounted_node_id;
+    const scope = edit.scope;
+
+    const element = this.top();
+    element.setAttribute(`dioxus-event-${event_name}`, `${scope}.${mounted_node_id}`);
+
+    console.log("listener map is", this.listeners);
+    if (this.listeners[event_name] === undefined) {
+      console.log("adding listener!");
+      this.listeners[event_name] = "bla";
+      this.root.addEventListener(event_name, (event) => {
+        const target = event.target;
+        const val = target.getAttribute(`dioxus-event-${event_name}`);
+        const fields = val.split(".");
+        const scope_id = parseInt(fields[0]);
+        const real_id = parseInt(fields[1]);
+
+        console.log(`parsed event with scope_id ${scope_id} and real_id ${real_id}`);
+
+        rpc.call('user_event', {
+          event: event_name,
+          scope: scope_id,
+          mounted_dom_id: real_id,
+        }).then((reply) => {
+          console.log(reply);
+          this.stack.push(this.root);
+
+          let edits = reply.edits;
+
+          for (let x = 0; x < edits.length; x++) {
+            let edit = edits[x];
+            console.log(edit);
+
+            let f = this[edit.type];
+            f.call(this, edit);
+          }
+
+          console.log("initiated");
+        }).catch((err) => {
+          console.log("failed to initiate", err);
+        });
+      });
+    }
+  }
+}
+
+async function initialize() {
+  const reply = await rpc.call('initiate');
+  let root = window.document.getElementById("_dioxusroot");
+  const interpreter = new Interpreter(root);
+  console.log(reply);
+
+  let pre_rendered = reply.pre_rendered;
+  if (pre_rendered !== undefined) {
+    root.innerHTML = pre_rendered;
+  }
+
+  const edits = reply.edits;
+
+  apply_edits(edits, interpreter);
+}
+
+function apply_edits(edits, interpreter) {
+  for (let x = 0; x < edits.length; x++) {
+    let edit = edits[x];
+    console.log(edit);
+    let f = interpreter[edit.type];
+    f.call(interpreter, edit);
+  }
+
+  console.log("stack completed: ", interpreter.stack);
+}
+
+initialize();

+ 159 - 111
packages/desktop/src/lib.rs

@@ -4,20 +4,28 @@
 //!
 //!
 
 
 use std::borrow::BorrowMut;
 use std::borrow::BorrowMut;
+use std::cell::RefCell;
 use std::ops::{Deref, DerefMut};
 use std::ops::{Deref, DerefMut};
+use std::rc::Rc;
 use std::sync::atomic::AtomicBool;
 use std::sync::atomic::AtomicBool;
 use std::sync::mpsc::channel;
 use std::sync::mpsc::channel;
 use std::sync::{Arc, RwLock};
 use std::sync::{Arc, RwLock};
 
 
 use cfg::DesktopConfig;
 use cfg::DesktopConfig;
+use dioxus_core::scheduler::SchedulerMsg;
 use dioxus_core::*;
 use dioxus_core::*;
+// use futures_channel::mpsc::UnboundedSender;
 use serde::{Deserialize, Serialize};
 use serde::{Deserialize, Serialize};
+
+mod logging;
+
+pub use logging::set_up_logging;
 pub use wry;
 pub use wry;
 
 
 use wry::application::event::{Event, WindowEvent};
 use wry::application::event::{Event, WindowEvent};
-use wry::application::event_loop::{ControlFlow, EventLoop};
+use wry::application::event_loop::{self, ControlFlow, EventLoop};
 use wry::application::window::Fullscreen;
 use wry::application::window::Fullscreen;
-use wry::webview::WebViewBuilder;
+use wry::webview::{WebView, WebViewBuilder};
 use wry::{
 use wry::{
     application::window::{Window, WindowBuilder},
     application::window::{Window, WindowBuilder},
     webview::{RpcRequest, RpcResponse},
     webview::{RpcRequest, RpcResponse},
@@ -45,10 +53,16 @@ pub fn launch_with_props<P: Properties + 'static + Send + Sync>(
     run(root, props, builder)
     run(root, props, builder)
 }
 }
 
 
+#[derive(Serialize)]
 enum RpcEvent<'a> {
 enum RpcEvent<'a> {
     Initialize { edits: Vec<DomEdit<'a>> },
     Initialize { edits: Vec<DomEdit<'a>> },
 }
 }
 
 
+enum BridgeEvent {
+    Initialize(serde_json::Value),
+    Update(serde_json::Value),
+}
+
 #[derive(Serialize)]
 #[derive(Serialize)]
 struct Response<'a> {
 struct Response<'a> {
     pre_rendered: Option<String>,
     pre_rendered: Option<String>,
@@ -60,72 +74,175 @@ pub fn run<T: Properties + 'static + Send + Sync>(
     props: T,
     props: T,
     user_builder: impl for<'a, 'b> FnOnce(&'b mut DesktopConfig<'a>) -> &'b mut DesktopConfig<'a>,
     user_builder: impl for<'a, 'b> FnOnce(&'b mut DesktopConfig<'a>) -> &'b mut DesktopConfig<'a>,
 ) -> anyhow::Result<()> {
 ) -> anyhow::Result<()> {
-    run_with_edits(root, props, user_builder, None)
-}
-
-pub fn run_with_edits<
-    F: for<'a, 'b> FnOnce(&'a mut DesktopConfig<'b>) -> &'a mut DesktopConfig<'b>,
-    T: Properties + 'static + Send + Sync,
->(
-    root: FC<T>,
-    props: T,
-    user_builder: F,
-    redits: Option<Vec<DomEdit<'static>>>,
-) -> anyhow::Result<()> {
-    /*
-
-
-    */
-
     let mut cfg = DesktopConfig::new();
     let mut cfg = DesktopConfig::new();
     user_builder(&mut cfg);
     user_builder(&mut cfg);
     let DesktopConfig {
     let DesktopConfig {
         window,
         window,
         manual_edits,
         manual_edits,
         pre_rendered,
         pre_rendered,
+        ..
     } = cfg;
     } = cfg;
 
 
     let event_loop = EventLoop::new();
     let event_loop = EventLoop::new();
     let window = window.build(&event_loop)?;
     let window = window.build(&event_loop)?;
 
 
-    let (event_tx, mut event_rx) = tokio::sync::mpsc::unbounded_channel::<String>();
+    let (event_tx, mut event_rx) = tokio::sync::mpsc::unbounded_channel();
+
+    let sender = launch_vdom_with_tokio(root, props, event_tx.clone());
+
+    let locked_receiver = Rc::new(RefCell::new(event_rx));
+
+    let webview = WebViewBuilder::new(window)?
+        .with_url("wry://src/index.html")?
+        .with_rpc_handler(move |_window: &Window, mut req: RpcRequest| {
+            match req.method.as_str() {
+                "initiate" => {
+                    //
+                    let mut rx = (*locked_receiver).borrow_mut();
+
+                    match rx.try_recv() {
+                        Ok(BridgeEvent::Initialize(edits)) => {
+                            Some(RpcResponse::new_result(req.id.take(), Some(edits)))
+                        }
+                        _ => None,
+                    }
+                }
+                "user_event" => {
+                    //
+                    let data = req.params.unwrap();
+                    log::debug!("Data: {:#?}", data);
+                    let event = events::trigger_from_serialized(data);
+                    sender.unbounded_send(SchedulerMsg::UiEvent(event)).unwrap();
+
+                    let mut rx = (*locked_receiver).borrow_mut();
+
+                    match rx.blocking_recv() {
+                        Some(BridgeEvent::Update(edits)) => {
+                            log::info!("Passing response back");
+                            Some(RpcResponse::new_result(req.id.take(), Some(edits)))
+                        }
+                        None => {
+                            log::error!("Sender half is gone");
+                            None
+                        }
+                        _ => {
+                            log::error!("No update event received");
+                            None
+                        }
+                    }
+                }
+                _ => todo!("this message failed"),
+            }
+        })
+        // this isn't quite portable unfortunately :(
+        // todo: figure out a way to allow us to create the index.html with the index.js file separately
+        // it's a bit easier to hack with
+        .with_custom_protocol("wry".into(), move |request| {
+            use std::fs::{canonicalize, read};
+            use wry::http::ResponseBuilder;
+            // Remove url scheme
+            let path = request.uri().replace("wry://", "");
+            // Read the file content from file path
+            let content = read(canonicalize(&path)?)?;
+
+            // Return asset contents and mime types based on file extentions
+            // If you don't want to do this manually, there are some crates for you.
+            // Such as `infer` and `mime_guess`.
+            let (data, meta) = if path.ends_with(".html") {
+                (content, "text/html")
+            } else if path.ends_with(".js") {
+                (content, "text/javascript")
+            } else if path.ends_with(".png") {
+                (content, "image/png")
+            } else {
+                unimplemented!();
+            };
+
+            ResponseBuilder::new().mimetype(meta).body(data)
+        })
+        .build()?;
+
+    run_event_loop(event_loop, webview, event_tx);
 
 
+    Ok(())
+}
+
+pub fn start<P: 'static + Send>(
+    root: FC<P>,
+    config_builder: impl for<'a, 'b> FnOnce(&'b mut DesktopConfig<'a>) -> &'b mut DesktopConfig<'a>,
+) -> ((), ()) {
+    //
+    ((), ())
+}
+
+// Create a new tokio runtime on a dedicated thread and then launch the apps VirtualDom.
+fn launch_vdom_with_tokio<C: Send + 'static>(
+    root: FC<C>,
+    props: C,
+    event_tx: tokio::sync::mpsc::UnboundedSender<BridgeEvent>,
+) -> futures_channel::mpsc::UnboundedSender<SchedulerMsg> {
     // Spawn the virtualdom onto its own thread
     // Spawn the virtualdom onto its own thread
     // if it wants to spawn multithreaded tasks, it can use the executor directly
     // if it wants to spawn multithreaded tasks, it can use the executor directly
+
+    let (sender, receiver) = futures_channel::mpsc::unbounded::<SchedulerMsg>();
+
+    let sender_2 = sender.clone();
     std::thread::spawn(move || {
     std::thread::spawn(move || {
-        //
-        let runtime = tokio::runtime::Builder::new_current_thread()
+        // We create the runtim as multithreaded, so you can still "spawn" onto multiple threads
+        let runtime = tokio::runtime::Builder::new_multi_thread()
             .enable_all()
             .enable_all()
             .build()
             .build()
             .unwrap();
             .unwrap();
 
 
         runtime.block_on(async move {
         runtime.block_on(async move {
-            let mut vir = VirtualDom::new_with_props(root, props);
-            let channel = vir.get_event_sender();
+            let mut vir = VirtualDom::new_with_props_and_scheduler(root, props, sender, receiver);
+            let _ = vir.get_event_sender();
+
+            let edits = vir.rebuild();
+
+            #[derive(Serialize)]
+            struct Evt<'a> {
+                edits: Vec<DomEdit<'a>>,
+            }
+
+            // let msg = RpcEvent::Initialize { edits: edits.edits };
+            let edit_string = serde_json::to_value(Evt { edits: edits.edits }).unwrap();
+            match event_tx.send(BridgeEvent::Initialize(edit_string)) {
+                Ok(_) => {}
+                Err(_) => {}
+            }
+
             loop {
             loop {
                 vir.wait_for_work().await;
                 vir.wait_for_work().await;
-                let edits = vir.run_with_deadline(|| false);
-                let edit_string = serde_json::to_string(&edits[0].edits).unwrap();
-                event_tx.send(edit_string).unwrap();
-            }
-        })
-    });
+                log::info!("{}", vir);
 
 
-    let dioxus_requsted = Arc::new(AtomicBool::new(false));
+                let mut muts = vir.run_with_deadline(|| false);
+                log::info!("muts {:#?}", muts);
+                while let Some(edit) = muts.pop() {
+                    let edit_string = serde_json::to_value(Evt { edits: edit.edits }).unwrap();
+                    match event_tx.send(BridgeEvent::Update(edit_string)) {
+                        Ok(_) => {}
+                        Err(er) => {
+                            log::error!("Sending should not fail {}", er);
+                        }
+                    }
+                }
 
 
-    let webview = WebViewBuilder::new(window)?
-        .with_url(&format!("data:text/html,{}", HTML_CONTENT))?
-        .with_rpc_handler(move |_window: &Window, mut req: RpcRequest| {
-            match req.method.as_str() {
-                "initiate" => {}
-                "user_event" => {}
-                _ => todo!("this message failed"),
+                log::info!("mutations sent on channel");
             }
             }
-            todo!()
         })
         })
-        .build()?;
+    });
+
+    sender_2
+}
 
 
-    event_loop.run(move |event, _, control_flow| {
+fn run_event_loop(
+    event_loop: EventLoop<()>,
+    webview: WebView,
+    event_tx: tokio::sync::mpsc::UnboundedSender<BridgeEvent>,
+) {
+    let _ = event_tx.clone();
+    event_loop.run(move |event, target, control_flow| {
         *control_flow = ControlFlow::Wait;
         *control_flow = ControlFlow::Wait;
 
 
         match event {
         match event {
@@ -146,74 +263,5 @@ pub fn run_with_edits<
 
 
             _ => {}
             _ => {}
         }
         }
-    });
-
-    Ok(())
+    })
 }
 }
-
-// let edits = if let Some(edits) = &redits {
-//     serde_json::to_value(edits).unwrap()
-// } else {
-//     let mut lock = vdom.write().unwrap();
-//     // let mut reg_lock = registry.write().unwrap();
-//     // Create the thin wrapper around the registry to collect the edits into
-//     let mut real = dom::WebviewDom::new();
-//     let pre = pre_rendered.clone();
-//     let response = match pre {
-//         Some(content) => {
-//             lock.rebuild_in_place().unwrap();
-//             Response {
-//                 edits: Vec::new(),
-//                 pre_rendered: Some(content),
-//             }
-//         }
-//         None => {
-//             //
-//             let edits = {
-//                 // let mut edits = Vec::new();
-//                 todo!()
-//                 // lock.rebuild(&mut real, &mut edits).unwrap();
-//                 // edits
-//             };
-//             Response {
-//                 edits,
-//                 pre_rendered: None,
-//             }
-//         }
-//     };
-//     serde_json::to_value(&response).unwrap()
-// };
-// // Return the edits into the webview runtime
-// Some(RpcResponse::new_result(req.id.take(), Some(edits)))
-
-// log::debug!("User event received");
-// // let registry = registry.clone();
-// let vdom = vdom.clone();
-// let response = async_std::task::block_on(async move {
-//     let mut lock = vdom.write().unwrap();
-//     // let mut reg_lock = registry.write().unwrap();
-//     // a deserialized event
-//     let data = req.params.unwrap();
-//     log::debug!("Data: {:#?}", data);
-//     let event = trigger_from_serialized(data);
-//     // lock.queue_event(event);
-//     // Create the thin wrapper around the registry to collect the edits into
-//     let mut real = dom::WebviewDom::new();
-//     // Serialize the edit stream
-//     //
-//     let mut edits = Vec::new();
-//     // lock.run(&mut real, &mut edits)
-//     //     .await
-//     //     .expect("failed to progress");
-//     let response = Response {
-//         edits,
-//         pre_rendered: None,
-//     };
-//     let response = serde_json::to_value(&response).unwrap();
-//     // Give back the registry into its slot
-//     // *reg_lock = Some(real.consume());
-//     // Return the edits into the webview runtime
-//     Some(RpcResponse::new_result(req.id.take(), Some(response)))
-// });
-// response
-// // spawn a task to clean up the garbage

+ 51 - 0
packages/desktop/src/logging.rs

@@ -0,0 +1,51 @@
+pub fn set_up_logging(enabled: bool) {
+    use fern::colors::{Color, ColoredLevelConfig};
+
+    if !enabled {
+        return;
+    }
+
+    // configure colors for the whole line
+    let colors_line = ColoredLevelConfig::new()
+        .error(Color::Red)
+        .warn(Color::Yellow)
+        // we actually don't need to specify the color for debug and info, they are white by default
+        .info(Color::White)
+        .debug(Color::White)
+        // depending on the terminals color scheme, this is the same as the background color
+        .trace(Color::BrightBlack);
+
+    // configure colors for the name of the level.
+    // since almost all of them are the same as the color for the whole line, we
+    // just clone `colors_line` and overwrite our changes
+    let colors_level = colors_line.clone().info(Color::Green);
+    // here we set up our fern Dispatch
+
+    // when running tests in batch, the logger is re-used, so ignore the logger error
+    let _ = fern::Dispatch::new()
+        .format(move |out, message, record| {
+            out.finish(format_args!(
+                "{color_line}[{level}{color_line}] {message}\x1B[0m",
+                color_line = format_args!(
+                    "\x1B[{}m",
+                    colors_line.get_color(&record.level()).to_fg_str()
+                ),
+                level = colors_level.color(record.level()),
+                message = message,
+            ));
+        })
+        // set the default log level. to filter out verbose log messages from dependencies, set
+        // this to Warn and overwrite the log level for your crate.
+        .level(log::LevelFilter::Debug)
+        // .level(log::LevelFilter::Warn)
+        // change log levels for individual modules. Note: This looks for the record's target
+        // field which defaults to the module path but can be overwritten with the `target`
+        // parameter:
+        // `info!(target="special_target", "This log message is about special_target");`
+        // .level_for("dioxus", log::LevelFilter::Debug)
+        // .level_for("dioxus", log::LevelFilter::Info)
+        // .level_for("pretty_colored", log::LevelFilter::Trace)
+        // output to stdout
+        .chain(std::io::stdout())
+        .apply();
+}

+ 1 - 1
packages/mobile/Cargo.toml

@@ -13,7 +13,7 @@ dioxus-core = { path = "../core", version = "0.1.2" }
 log = "0.4.14"
 log = "0.4.14"
 serde = "1.0.126"
 serde = "1.0.126"
 serde_json = "1.0.64"
 serde_json = "1.0.64"
-wry = "0.11.0"
+wry = "0.12.2"
 
 
 
 
 [target.'cfg(target_os = "android")'.dependencies]
 [target.'cfg(target_os = "android")'.dependencies]

+ 1 - 1
packages/web/Cargo.toml

@@ -72,9 +72,9 @@ crate-type = ["cdylib", "rlib"]
 im-rc = "15.0.0"
 im-rc = "15.0.0"
 separator = "0.4.1"
 separator = "0.4.1"
 uuid = { version = "0.8.2", features = ["v4", "wasm-bindgen"] }
 uuid = { version = "0.8.2", features = ["v4", "wasm-bindgen"] }
-dioxus-hooks = { path = "../hooks" }
 serde = { version = "1.0.126", features = ["derive"] }
 serde = { version = "1.0.126", features = ["derive"] }
 reqwest = { version = "0.11", features = ["json"] }
 reqwest = { version = "0.11", features = ["json"] }
+dioxus-hooks = { path = "../hooks" }
 dioxus-core-macro = { path = "../core-macro" }
 dioxus-core-macro = { path = "../core-macro" }
 # rand = { version="0.8.4", features=["small_rng"] }
 # rand = { version="0.8.4", features=["small_rng"] }
 # surf = { version = "2.3.1", default-features = false, features = [
 # surf = { version = "2.3.1", default-features = false, features = [

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

@@ -44,9 +44,9 @@ static App: FC<()> = |cx, props| {
                         "dynamic subtree {state}"
                         "dynamic subtree {state}"
                     }
                     }
                     div {
                     div {
-                        button { onclick: move |_| state+=1, "incr" }
+                        button { onclick: move |e| state+=1, "incr" }
                         br {}
                         br {}
-                        button { onclick: move |_| state-=1, "decr" }
+                        button { onclick: move |e| state-=1, "decr" }
                     }
                     }
                 }
                 }
             }
             }

+ 180 - 59
packages/web/src/dom.rs

@@ -8,7 +8,7 @@
 //! - Partial delegation?>
 //! - Partial delegation?>
 
 
 use dioxus_core::{
 use dioxus_core::{
-    events::{SyntheticEvent, UserEvent},
+    events::{DioxusEvent, KeyCode, SyntheticEvent, UserEvent},
     mutations::NodeRefMutation,
     mutations::NodeRefMutation,
     scheduler::SchedulerMsg,
     scheduler::SchedulerMsg,
     DomEdit, ElementId, ScopeId,
     DomEdit, ElementId, ScopeId,
@@ -110,7 +110,6 @@ impl WebsysDom {
                 DomEdit::AppendChildren { many } => self.append_children(many),
                 DomEdit::AppendChildren { many } => self.append_children(many),
                 DomEdit::ReplaceWith { m, root } => self.replace_with(m, root),
                 DomEdit::ReplaceWith { m, root } => self.replace_with(m, root),
                 DomEdit::Remove { root } => self.remove(root),
                 DomEdit::Remove { root } => self.remove(root),
-                DomEdit::RemoveAllChildren => self.remove_all_children(),
                 DomEdit::CreateTextNode { text, id } => self.create_text_node(text, id),
                 DomEdit::CreateTextNode { text, id } => self.create_text_node(text, id),
                 DomEdit::CreateElement { tag, id } => self.create_element(tag, None, id),
                 DomEdit::CreateElement { tag, id } => self.create_element(tag, None, id),
                 DomEdit::CreateElementNs { tag, id, ns } => self.create_element(tag, Some(ns), id),
                 DomEdit::CreateElementNs { tag, id, ns } => self.create_element(tag, Some(ns), id),
@@ -208,10 +207,6 @@ impl WebsysDom {
         }
         }
     }
     }
 
 
-    fn remove_all_children(&mut self) {
-        todo!()
-    }
-
     fn create_placeholder(&mut self, id: u64) {
     fn create_placeholder(&mut self, id: u64) {
         self.create_element("pre", None, id);
         self.create_element("pre", None, id);
         self.set_attribute("hidden", "", None);
         self.set_attribute("hidden", "", None);
@@ -464,87 +459,213 @@ impl Stack {
     }
     }
 }
 }
 
 
+pub struct DioxusWebsysEvent(web_sys::Event);
+unsafe impl Send for DioxusWebsysEvent {}
+unsafe impl Sync for DioxusWebsysEvent {}
+
+// trait MyTrait {}
+// impl MyTrait for web_sys::Event {}
+
 // todo: some of these events are being casted to the wrong event type.
 // 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.
 // 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) -> SyntheticEvent {
     use crate::events::*;
     use crate::events::*;
     use dioxus_core::events::on::*;
     use dioxus_core::events::on::*;
     match event.type_().as_str() {
     match event.type_().as_str() {
-        "copy" | "cut" | "paste" => {
-            SyntheticEvent::ClipboardEvent(ClipboardEvent(Arc::new(WebsysClipboardEvent(event))))
-        }
+        "copy" | "cut" | "paste" => SyntheticEvent::ClipboardEvent(ClipboardEvent(
+            DioxusEvent::new(ClipboardEventInner(), DioxusWebsysEvent(event)),
+        )),
         "compositionend" | "compositionstart" | "compositionupdate" => {
         "compositionend" | "compositionstart" | "compositionupdate" => {
-            let evt: web_sys::CompositionEvent = event.dyn_into().unwrap();
-            SyntheticEvent::CompositionEvent(CompositionEvent(Arc::new(WebsysCompositionEvent(
-                evt,
-            ))))
+            let evt: &web_sys::CompositionEvent = event.dyn_ref().unwrap();
+            SyntheticEvent::CompositionEvent(CompositionEvent(DioxusEvent::new(
+                CompositionEventInner {
+                    data: evt.data().unwrap_or_default(),
+                },
+                DioxusWebsysEvent(event),
+            )))
         }
         }
         "keydown" | "keypress" | "keyup" => {
         "keydown" | "keypress" | "keyup" => {
-            let evt: web_sys::KeyboardEvent = event.dyn_into().unwrap();
-            SyntheticEvent::KeyboardEvent(KeyboardEvent(Arc::new(WebsysKeyboardEvent(evt))))
-        }
-        "focus" | "blur" => {
-            let evt: web_sys::FocusEvent = event.dyn_into().unwrap();
-            SyntheticEvent::FocusEvent(FocusEvent(Arc::new(WebsysFocusEvent(evt))))
-        }
-        "change" => {
-            let evt = event.dyn_into().unwrap();
-            SyntheticEvent::GenericEvent(GenericEvent(Arc::new(WebsysGenericUiEvent(evt))))
-        }
+            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),
+            )))
+        }
+        "focus" | "blur" => SyntheticEvent::FocusEvent(FocusEvent(DioxusEvent::new(
+            FocusEventInner {},
+            DioxusWebsysEvent(event),
+        ))),
+        "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" => {
         "input" | "invalid" | "reset" | "submit" => {
-            let evt: web_sys::Event = event.dyn_into().unwrap();
-            SyntheticEvent::FormEvent(FormEvent(Arc::new(WebsysFormEvent(evt))))
+            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())
+                .or_else(|| {
+                    target
+                        .dyn_ref()
+                        .map(|input: &web_sys::HtmlTextAreaElement| input.value())
+                })
+                // select elements are NOT input events - because - why woudn't they be??
+                .or_else(|| {
+                    target
+                        .dyn_ref()
+                        .map(|input: &web_sys::HtmlSelectElement| input.value())
+                })
+                .or_else(|| {
+                    target
+                        .dyn_ref::<web_sys::HtmlElement>()
+                        .unwrap()
+                        .text_content()
+                })
+                .expect("only an InputElement or TextAreaElement or an element with contenteditable=true can have an oninput event listener");
+
+            SyntheticEvent::FormEvent(FormEvent(DioxusEvent::new(
+                FormEventInner { value },
+                DioxusWebsysEvent(event),
+            )))
         }
         }
         "click" | "contextmenu" | "doubleclick" | "drag" | "dragend" | "dragenter" | "dragexit"
         "click" | "contextmenu" | "doubleclick" | "drag" | "dragend" | "dragenter" | "dragexit"
         | "dragleave" | "dragover" | "dragstart" | "drop" | "mousedown" | "mouseenter"
         | "dragleave" | "dragover" | "dragstart" | "drop" | "mousedown" | "mouseenter"
         | "mouseleave" | "mousemove" | "mouseout" | "mouseover" | "mouseup" => {
         | "mouseleave" | "mousemove" | "mouseout" | "mouseover" | "mouseup" => {
-            let evt: web_sys::MouseEvent = event.dyn_into().unwrap();
-            SyntheticEvent::MouseEvent(MouseEvent(Arc::new(WebsysMouseEvent(evt))))
+            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),
+            )))
         }
         }
         "pointerdown" | "pointermove" | "pointerup" | "pointercancel" | "gotpointercapture"
         "pointerdown" | "pointermove" | "pointerup" | "pointercancel" | "gotpointercapture"
         | "lostpointercapture" | "pointerenter" | "pointerleave" | "pointerover" | "pointerout" => {
         | "lostpointercapture" | "pointerenter" | "pointerleave" | "pointerover" | "pointerout" => {
-            let evt: web_sys::PointerEvent = event.dyn_into().unwrap();
-            SyntheticEvent::PointerEvent(PointerEvent(Arc::new(WebsysPointerEvent(evt))))
-        }
-        "select" => {
-            let evt: web_sys::UiEvent = event.dyn_into().unwrap();
-            SyntheticEvent::SelectionEvent(SelectionEvent(Arc::new(WebsysGenericUiEvent(evt))))
-        }
+            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),
+            )))
+        }
+        "select" => SyntheticEvent::SelectionEvent(SelectionEvent(DioxusEvent::new(
+            SelectionEventInner {},
+            DioxusWebsysEvent(event),
+        ))),
+
         "touchcancel" | "touchend" | "touchmove" | "touchstart" => {
         "touchcancel" | "touchend" | "touchmove" | "touchstart" => {
-            let evt: web_sys::TouchEvent = event.dyn_into().unwrap();
-            SyntheticEvent::TouchEvent(TouchEvent(Arc::new(WebsysTouchEvent(evt))))
-        }
-        "scroll" => {
-            let evt: web_sys::UiEvent = event.dyn_into().unwrap();
-            SyntheticEvent::GenericEvent(GenericEvent(Arc::new(WebsysGenericUiEvent(evt))))
+            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),
+            )))
         }
         }
+
+        "scroll" => SyntheticEvent::GenericEvent(DioxusEvent::new((), DioxusWebsysEvent(event))),
+
         "wheel" => {
         "wheel" => {
-            let evt: web_sys::WheelEvent = event.dyn_into().unwrap();
-            SyntheticEvent::WheelEvent(WheelEvent(Arc::new(WebsysWheelEvent(evt))))
+            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),
+            )))
         }
         }
+
         "animationstart" | "animationend" | "animationiteration" => {
         "animationstart" | "animationend" | "animationiteration" => {
-            let evt: web_sys::AnimationEvent = event.dyn_into().unwrap();
-            SyntheticEvent::AnimationEvent(AnimationEvent(Arc::new(WebsysAnimationEvent(evt))))
+            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),
+            )))
         }
         }
+
         "transitionend" => {
         "transitionend" => {
-            let evt: web_sys::TransitionEvent = event.dyn_into().unwrap();
-            SyntheticEvent::TransitionEvent(TransitionEvent(Arc::new(WebsysTransitionEvent(evt))))
+            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),
+            )))
         }
         }
+
         "abort" | "canplay" | "canplaythrough" | "durationchange" | "emptied" | "encrypted"
         "abort" | "canplay" | "canplaythrough" | "durationchange" | "emptied" | "encrypted"
         | "ended" | "error" | "loadeddata" | "loadedmetadata" | "loadstart" | "pause" | "play"
         | "ended" | "error" | "loadeddata" | "loadedmetadata" | "loadstart" | "pause" | "play"
         | "playing" | "progress" | "ratechange" | "seeked" | "seeking" | "stalled" | "suspend"
         | "playing" | "progress" | "ratechange" | "seeked" | "seeking" | "stalled" | "suspend"
-        | "timeupdate" | "volumechange" | "waiting" => {
-            let evt: web_sys::UiEvent = event.dyn_into().unwrap();
-            SyntheticEvent::MediaEvent(MediaEvent(Arc::new(WebsysMediaEvent(evt))))
-        }
-        "toggle" => {
-            let evt: web_sys::UiEvent = event.dyn_into().unwrap();
-            SyntheticEvent::ToggleEvent(ToggleEvent(Arc::new(WebsysToggleEvent(evt))))
-        }
-        _ => {
-            let evt: web_sys::UiEvent = event.dyn_into().unwrap();
-            SyntheticEvent::GenericEvent(GenericEvent(Arc::new(WebsysGenericUiEvent(evt))))
-        }
+        | "timeupdate" | "volumechange" | "waiting" => SyntheticEvent::MediaEvent(MediaEvent(
+            DioxusEvent::new(MediaEventInner {}, DioxusWebsysEvent(event)),
+        )),
+
+        "toggle" => SyntheticEvent::ToggleEvent(ToggleEvent(DioxusEvent::new(
+            ToggleEventInner {},
+            DioxusWebsysEvent(event),
+        ))),
+
+        _ => SyntheticEvent::GenericEvent(DioxusEvent::new((), DioxusWebsysEvent(event))),
     }
     }
 }
 }
 
 

+ 0 - 477
packages/web/src/events.rs

@@ -3,480 +3,3 @@
 use dioxus_core::events::on::*;
 use dioxus_core::events::on::*;
 use wasm_bindgen::JsCast;
 use wasm_bindgen::JsCast;
 use web_sys::{Event, UiEvent};
 use web_sys::{Event, UiEvent};
-
-/// All events implement the generic event type - they're all `UI events`
-trait WebsysGenericEvent {
-    fn as_ui_event(&self) -> &UiEvent;
-}
-
-impl GenericEventInner for &dyn WebsysGenericEvent {
-    /// On WebSys, this returns an &UiEvent which can be casted via dyn_ref into the correct sub type.
-    fn raw_event(&self) -> &dyn std::any::Any {
-        self.as_ui_event()
-    }
-
-    fn bubbles(&self) -> bool {
-        self.as_ui_event().bubbles()
-    }
-
-    fn cancel_bubble(&self) {
-        self.as_ui_event().cancel_bubble();
-    }
-
-    fn cancelable(&self) -> bool {
-        self.as_ui_event().cancelable()
-    }
-
-    fn composed(&self) -> bool {
-        self.as_ui_event().composed()
-    }
-
-    fn current_target(&self) {
-        if cfg!(debug_assertions) {
-            todo!("Current target does not return anything useful.\nPlease try casting the event directly.");
-        }
-        // self.as_ui_event().current_target();
-    }
-
-    fn default_prevented(&self) -> bool {
-        self.as_ui_event().default_prevented()
-    }
-
-    fn event_phase(&self) -> u16 {
-        self.as_ui_event().event_phase()
-    }
-
-    fn is_trusted(&self) -> bool {
-        self.as_ui_event().is_trusted()
-    }
-
-    fn prevent_default(&self) {
-        self.as_ui_event().prevent_default()
-    }
-
-    fn stop_immediate_propagation(&self) {
-        self.as_ui_event().stop_immediate_propagation()
-    }
-
-    fn stop_propagation(&self) {
-        self.as_ui_event().stop_propagation()
-    }
-
-    fn target(&self) {
-        todo!()
-    }
-
-    fn time_stamp(&self) -> f64 {
-        self.as_ui_event().time_stamp()
-    }
-}
-
-macro_rules! implement_generic_event {
-    (
-        $($event:ident),*
-    ) => {
-        $(
-            impl WebsysGenericEvent for $event {
-                fn as_ui_event(&self) -> &UiEvent {
-                    self.0.dyn_ref().unwrap()
-                }
-            }
-        )*
-    };
-}
-
-implement_generic_event! {
-    WebsysClipboardEvent,
-    WebsysCompositionEvent,
-    WebsysKeyboardEvent,
-    WebsysGenericUiEvent,
-    WebsysFocusEvent,
-    WebsysFormEvent,
-    WebsysMouseEvent,
-    WebsysPointerEvent,
-    WebsysWheelEvent,
-    WebsysAnimationEvent,
-    WebsysTransitionEvent,
-    WebsysTouchEvent,
-    WebsysMediaEvent,
-    WebsysToggleEvent
-}
-
-// unfortunately, currently experimental, and web_sys needs to be configured to use it :>(
-pub struct WebsysClipboardEvent(pub Event);
-
-impl ClipboardEventInner for WebsysClipboardEvent {}
-
-pub struct WebsysCompositionEvent(pub web_sys::CompositionEvent);
-
-impl CompositionEventInner for WebsysCompositionEvent {
-    fn data(&self) -> String {
-        self.0.data().unwrap_or_else(|| String::new())
-    }
-}
-
-pub struct WebsysKeyboardEvent(pub web_sys::KeyboardEvent);
-impl KeyboardEventInner for WebsysKeyboardEvent {
-    fn alt_key(&self) -> bool {
-        self.0.alt_key()
-    }
-    fn char_code(&self) -> u32 {
-        self.0.char_code()
-    }
-    fn key(&self) -> String {
-        self.0.key()
-    }
-
-    fn key_code(&self) -> KeyCode {
-        KeyCode::from_raw_code(self.0.key_code() as u8)
-    }
-
-    fn ctrl_key(&self) -> bool {
-        self.0.ctrl_key()
-    }
-
-    fn get_modifier_state(&self, key_code: &str) -> bool {
-        self.0.get_modifier_state(key_code)
-    }
-
-    fn locale(&self) -> String {
-        if cfg!(debug_assertions) {
-            todo!("Locale is currently not supported. :(")
-        } else {
-            String::from("en-US")
-        }
-    }
-
-    fn location(&self) -> usize {
-        self.0.location() as usize
-    }
-
-    fn meta_key(&self) -> bool {
-        self.0.meta_key()
-    }
-
-    fn repeat(&self) -> bool {
-        self.0.repeat()
-    }
-
-    fn shift_key(&self) -> bool {
-        self.0.shift_key()
-    }
-
-    fn which(&self) -> usize {
-        self.0.which() as usize
-    }
-}
-
-pub struct WebsysGenericUiEvent(pub UiEvent);
-impl GenericEventInner for WebsysGenericUiEvent {
-    fn raw_event(&self) -> &dyn std::any::Any {
-        // self.0.raw_event()
-        todo!()
-    }
-
-    fn bubbles(&self) -> bool {
-        self.0.bubbles()
-    }
-
-    fn cancel_bubble(&self) {
-        self.0.cancel_bubble();
-    }
-
-    fn cancelable(&self) -> bool {
-        self.0.cancelable()
-    }
-
-    fn composed(&self) -> bool {
-        self.0.composed()
-    }
-
-    fn current_target(&self) {
-        // self.0.current_target()
-    }
-
-    fn default_prevented(&self) -> bool {
-        self.0.default_prevented()
-    }
-
-    fn event_phase(&self) -> u16 {
-        self.0.event_phase()
-    }
-
-    fn is_trusted(&self) -> bool {
-        self.0.is_trusted()
-    }
-
-    fn prevent_default(&self) {
-        self.0.prevent_default()
-    }
-
-    fn stop_immediate_propagation(&self) {
-        self.0.stop_immediate_propagation()
-    }
-
-    fn stop_propagation(&self) {
-        self.0.stop_propagation()
-    }
-
-    fn target(&self) {
-        // self.0.target()
-    }
-
-    fn time_stamp(&self) -> f64 {
-        self.0.time_stamp()
-    }
-}
-
-impl UIEventInner for WebsysGenericUiEvent {
-    fn detail(&self) -> i32 {
-        todo!()
-    }
-}
-
-impl SelectionEventInner for WebsysGenericUiEvent {}
-
-pub struct WebsysFocusEvent(pub web_sys::FocusEvent);
-impl FocusEventInner for WebsysFocusEvent {}
-
-pub struct WebsysFormEvent(pub web_sys::Event);
-impl FormEventInner for WebsysFormEvent {
-    // technically a controlled component, so we need to manually grab out the target data
-    fn value(&self) -> String {
-        let this: web_sys::EventTarget = self.0.target().unwrap();
-        (&this)
-                .dyn_ref()
-                .map(|input: &web_sys::HtmlInputElement| input.value())
-                .or_else(|| {
-                    this
-                        .dyn_ref()
-                        .map(|input: &web_sys::HtmlTextAreaElement| input.value())
-                })
-                // select elements are NOT input events - because - why woudn't they be??
-                .or_else(|| {
-                    this
-                        .dyn_ref()
-                        .map(|input: &web_sys::HtmlSelectElement| input.value())
-                })
-                .or_else(|| {
-                    this
-                        .dyn_ref::<web_sys::HtmlElement>()
-                        .unwrap()
-                        .text_content()
-                })
-                .expect("only an InputElement or TextAreaElement or an element with contenteditable=true can have an oninput event listener")
-    }
-}
-
-pub struct WebsysMouseEvent(pub web_sys::MouseEvent);
-impl MouseEventInner for WebsysMouseEvent {
-    fn alt_key(&self) -> bool {
-        self.0.alt_key()
-    }
-    fn button(&self) -> i16 {
-        self.0.button()
-    }
-    fn buttons(&self) -> u16 {
-        self.0.buttons()
-    }
-    fn client_x(&self) -> i32 {
-        self.0.client_x()
-    }
-    fn client_y(&self) -> i32 {
-        self.0.client_y()
-    }
-    fn ctrl_key(&self) -> bool {
-        self.0.ctrl_key()
-    }
-    fn meta_key(&self) -> bool {
-        self.0.meta_key()
-    }
-    fn page_x(&self) -> i32 {
-        self.0.page_x()
-    }
-    fn page_y(&self) -> i32 {
-        self.0.page_y()
-    }
-    fn screen_x(&self) -> i32 {
-        self.0.screen_x()
-    }
-    fn screen_y(&self) -> i32 {
-        self.0.screen_y()
-    }
-    fn shift_key(&self) -> bool {
-        self.0.shift_key()
-    }
-
-    // yikes
-    // https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/key/Key_Values
-    fn get_modifier_state(&self, key_code: &str) -> bool {
-        self.0.get_modifier_state(key_code)
-    }
-}
-
-pub struct WebsysPointerEvent(pub web_sys::PointerEvent);
-impl PointerEventInner for WebsysPointerEvent {
-    fn alt_key(&self) -> bool {
-        self.0.alt_key()
-    }
-    fn button(&self) -> i16 {
-        self.0.button()
-    }
-    fn buttons(&self) -> u16 {
-        self.0.buttons()
-    }
-    fn client_x(&self) -> i32 {
-        self.0.client_x()
-    }
-    fn client_y(&self) -> i32 {
-        self.0.client_y()
-    }
-    fn ctrl_key(&self) -> bool {
-        self.0.ctrl_key()
-    }
-    fn meta_key(&self) -> bool {
-        self.0.meta_key()
-    }
-    fn page_x(&self) -> i32 {
-        self.0.page_x()
-    }
-    fn page_y(&self) -> i32 {
-        self.0.page_y()
-    }
-    fn screen_x(&self) -> i32 {
-        self.0.screen_x()
-    }
-    fn screen_y(&self) -> i32 {
-        self.0.screen_y()
-    }
-    fn shift_key(&self) -> bool {
-        self.0.shift_key()
-    }
-
-    // yikes
-    // https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/key/Key_Values
-    fn get_modifier_state(&self, key_code: &str) -> bool {
-        self.0.get_modifier_state(key_code)
-    }
-
-    fn pointer_id(&self) -> i32 {
-        self.0.pointer_id()
-    }
-
-    fn width(&self) -> i32 {
-        self.0.width()
-    }
-
-    fn height(&self) -> i32 {
-        self.0.height()
-    }
-
-    fn pressure(&self) -> f32 {
-        self.0.pressure()
-    }
-
-    fn tangential_pressure(&self) -> f32 {
-        self.0.tangential_pressure()
-    }
-
-    fn tilt_x(&self) -> i32 {
-        self.0.tilt_x()
-    }
-
-    fn tilt_y(&self) -> i32 {
-        self.0.tilt_y()
-    }
-
-    fn twist(&self) -> i32 {
-        self.0.twist()
-    }
-
-    fn pointer_type(&self) -> String {
-        self.0.pointer_type()
-    }
-
-    fn is_primary(&self) -> bool {
-        self.0.is_primary()
-    }
-}
-
-pub struct WebsysWheelEvent(pub web_sys::WheelEvent);
-impl WheelEventInner for WebsysWheelEvent {
-    fn delta_mode(&self) -> u32 {
-        self.0.delta_mode()
-    }
-
-    fn delta_x(&self) -> f64 {
-        self.0.delta_x()
-    }
-
-    fn delta_y(&self) -> f64 {
-        self.0.delta_y()
-    }
-
-    fn delta_z(&self) -> f64 {
-        self.0.delta_z()
-    }
-}
-pub struct WebsysAnimationEvent(pub web_sys::AnimationEvent);
-impl AnimationEventInner for WebsysAnimationEvent {
-    fn animation_name(&self) -> String {
-        self.0.animation_name()
-    }
-
-    fn pseudo_element(&self) -> String {
-        self.0.pseudo_element()
-    }
-
-    fn elapsed_time(&self) -> f32 {
-        self.0.elapsed_time()
-    }
-}
-
-pub struct WebsysTransitionEvent(pub web_sys::TransitionEvent);
-impl TransitionEventInner for WebsysTransitionEvent {
-    fn property_name(&self) -> String {
-        self.0.property_name()
-    }
-
-    fn pseudo_element(&self) -> String {
-        self.0.pseudo_element()
-    }
-
-    fn elapsed_time(&self) -> f32 {
-        self.0.elapsed_time()
-    }
-}
-
-pub struct WebsysTouchEvent(pub web_sys::TouchEvent);
-impl TouchEventInner for WebsysTouchEvent {
-    fn alt_key(&self) -> bool {
-        self.0.alt_key()
-    }
-
-    fn ctrl_key(&self) -> bool {
-        self.0.ctrl_key()
-    }
-
-    fn meta_key(&self) -> bool {
-        self.0.meta_key()
-    }
-
-    fn shift_key(&self) -> bool {
-        self.0.shift_key()
-    }
-
-    fn get_modifier_state(&self, key_code: &str) -> bool {
-        if cfg!(debug_assertions) {
-            todo!("get_modifier_state is not currently supported for touch events");
-        } else {
-            false
-        }
-    }
-}
-
-pub struct WebsysMediaEvent(pub web_sys::UiEvent);
-impl MediaEventInner for WebsysMediaEvent {}
-
-pub struct WebsysToggleEvent(pub web_sys::UiEvent);
-impl ToggleEventInner for WebsysToggleEvent {}

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

@@ -116,7 +116,7 @@ pub fn launch(root_component: FC<()>, configuration: impl FnOnce(WebConfig) -> W
 /// ```
 /// ```
 pub fn launch_with_props<T, F>(root_component: FC<T>, root_properties: T, configuration_builder: F)
 pub fn launch_with_props<T, F>(root_component: FC<T>, root_properties: T, configuration_builder: F)
 where
 where
-    T: Properties + 'static,
+    T: Send + 'static,
     F: FnOnce(WebConfig) -> WebConfig,
     F: FnOnce(WebConfig) -> WebConfig,
 {
 {
     let config = configuration_builder(WebConfig::default());
     let config = configuration_builder(WebConfig::default());
@@ -135,7 +135,7 @@ where
 ///     wasm_bindgen_futures::spawn_local(app_fut);
 ///     wasm_bindgen_futures::spawn_local(app_fut);
 /// }
 /// }
 /// ```
 /// ```
-pub async fn run_with_props<T: Properties + 'static>(root: FC<T>, root_props: T, cfg: WebConfig) {
+pub async fn run_with_props<T: 'static + Send>(root: FC<T>, root_props: T, cfg: WebConfig) {
     let mut dom = VirtualDom::new_with_props(root, root_props);
     let mut dom = VirtualDom::new_with_props(root, root_props);
 
 
     intern_cached_strings();
     intern_cached_strings();

+ 8 - 0
packages/webview-client/Cargo.toml

@@ -0,0 +1,8 @@
+[package]
+name = "dioxus-webview-client"
+version = "0.0.0"
+edition = "2018"
+
+# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
+
+[dependencies]

+ 8 - 0
packages/webview-client/README.md

@@ -0,0 +1,8 @@
+# the client part of the vdom
+
+
+this crate is designed to be the "receiving end" of the dioxus virtualdom, using wasm_bindgen to expose an API for the receiving end.
+
+
+
+

+ 3 - 0
packages/webview-client/src/main.rs

@@ -0,0 +1,3 @@
+fn main() {
+    println!("Hello, world!");
+}