瀏覽代碼

feat: add proper event type

Jonathan Kelley 2 年之前
父節點
當前提交
50faa7dd08

+ 7 - 0
packages/desktop/src/main.js

@@ -0,0 +1,7 @@
+export function main(rootname = "main") {
+  let root = window.document.getElementById(rootname);
+  if (root != null) {
+    window.interpreter = new Interpreter(root);
+    window.ipc.postMessage(serializeIpcMessage("initialize"));
+  }
+}

+ 6 - 2
packages/html/Cargo.toml

@@ -19,6 +19,7 @@ euclid = "0.22.7"
 enumset = "1.0.11"
 keyboard-types = "0.6.2"
 async-trait = "0.1.58"
+serde-value = "0.7.0"
 
 [dependencies.web-sys]
 optional = true
@@ -39,7 +40,10 @@ features = [
     "ClipboardEvent",
 ]
 
+[dev-dependencies]
+serde_json = "*"
+
 [features]
-default = []
-serialize = ["serde", "serde_repr", "euclid/serde", "keyboard-types/serde"]
+default = ["serialize"]
+serialize = ["serde", "serde_repr", "euclid/serde", "keyboard-types/serde", "dioxus-core/serialize"]
 wasm-bind = ["web-sys", "wasm-bindgen"]

+ 1 - 1
packages/html/src/events/animation.rs

@@ -3,7 +3,7 @@ use dioxus_core::Event;
 pub type AnimationEvent = Event<AnimationData>;
 
 #[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
-#[derive(Debug, Clone)]
+#[derive(Debug, Clone, PartialEq)]
 pub struct AnimationData {
     pub animation_name: String,
     pub pseudo_element: String,

+ 1 - 1
packages/html/src/events/clipboard.rs

@@ -2,7 +2,7 @@ use dioxus_core::Event;
 
 pub type ClipboardEvent = Event<ClipboardData>;
 #[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
-#[derive(Debug, Clone)]
+#[derive(Debug, Clone, PartialEq, Eq)]
 pub struct ClipboardData {
     // DOMDataTransfer clipboardData
 }

+ 1 - 1
packages/html/src/events/composition.rs

@@ -2,7 +2,7 @@ use dioxus_core::Event;
 
 pub type CompositionEvent = Event<CompositionData>;
 #[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
-#[derive(Debug, Clone)]
+#[derive(Debug, Clone, PartialEq, Eq)]
 pub struct CompositionData {
     pub data: String,
 }

+ 2 - 5
packages/html/src/events/drag.rs

@@ -1,5 +1,3 @@
-use std::any::Any;
-
 use dioxus_core::Event;
 
 use crate::MouseData;
@@ -10,12 +8,11 @@ pub type DragEvent = Event<DragData>;
 /// placing a pointer device (such as a mouse) on the touch surface and then dragging the pointer to a new location
 /// (such as another DOM element). Applications are free to interpret a drag and drop interaction in an
 /// application-specific way.
+#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
+#[derive(Debug, Clone, PartialEq)]
 pub struct DragData {
     /// Inherit mouse data
     pub mouse: MouseData,
-
-    /// And then add the rest of the drag data
-    pub data: Box<dyn Any>,
 }
 
 impl_event! {

+ 1 - 1
packages/html/src/events/focus.rs

@@ -3,7 +3,7 @@ use dioxus_core::Event;
 pub type FocusEvent = Event<FocusData>;
 
 #[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
-#[derive(Debug, Clone)]
+#[derive(Debug, Clone, PartialEq, Eq)]
 pub struct FocusData {/* DOMEventInner:  Send + SyncTarget relatedTarget */}
 
 impl_event! [

+ 13 - 14
packages/html/src/events/form.rs

@@ -1,4 +1,4 @@
-use std::{collections::HashMap, fmt::Debug, sync::Arc};
+use std::{collections::HashMap, fmt::Debug};
 
 use dioxus_core::Event;
 
@@ -6,14 +6,13 @@ pub type FormEvent = Event<FormData>;
 
 /* DOMEvent:  Send + SyncTarget relatedTarget */
 #[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
-#[derive(Clone)]
+#[derive(Clone, PartialEq, Default)]
 pub struct FormData {
     pub value: String,
 
     pub values: HashMap<String, String>,
-
-    #[cfg_attr(feature = "serialize", serde(skip))]
-    pub files: Option<Arc<dyn FileEngine>>,
+    // #[cfg_attr(feature = "serialize", serde(skip))]
+    // pub files: Option<Arc<dyn FileEngine>>,
 }
 
 impl Debug for FormData {
@@ -25,17 +24,17 @@ impl Debug for FormData {
     }
 }
 
-#[async_trait::async_trait(?Send)]
-pub trait FileEngine {
-    // get a list of file names
-    fn files(&self) -> Vec<String>;
+// #[async_trait::async_trait(?Send)]
+// pub trait FileEngine {
+//     // get a list of file names
+//     fn files(&self) -> Vec<String>;
 
-    // read a file to bytes
-    async fn read_file(&self, file: &str) -> Option<Vec<u8>>;
+//     // read a file to bytes
+//     async fn read_file(&self, file: &str) -> Option<Vec<u8>>;
 
-    // read a file to string
-    async fn read_file_to_string(&self, file: &str) -> Option<String>;
-}
+//     // read a file to string
+//     async fn read_file_to_string(&self, file: &str) -> Option<String>;
+// }
 
 impl_event! {
     FormData;

+ 1 - 1
packages/html/src/events/image.rs

@@ -2,7 +2,7 @@ use dioxus_core::Event;
 
 pub type ImageEvent = Event<ImageData>;
 #[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
-#[derive(Debug, Clone)]
+#[derive(Debug, Clone, PartialEq, Eq)]
 pub struct ImageData {
     pub load_error: bool,
 }

+ 1 - 1
packages/html/src/events/keyboard.rs

@@ -7,7 +7,7 @@ use std::str::FromStr;
 
 pub type KeyboardEvent = Event<KeyboardData>;
 #[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
-#[derive(Clone)]
+#[derive(Clone, PartialEq, Eq)]
 pub struct KeyboardData {
     #[deprecated(
         since = "0.3.0",

+ 1 - 1
packages/html/src/events/media.rs

@@ -2,7 +2,7 @@ use dioxus_core::Event;
 
 pub type MediaEvent = Event<MediaData>;
 #[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
-#[derive(Debug, Clone)]
+#[derive(Debug, Clone, PartialEq, Eq)]
 pub struct MediaData {}
 
 impl_event! [

+ 1 - 1
packages/html/src/events/mouse.rs

@@ -10,7 +10,7 @@ pub type MouseEvent = Event<MouseData>;
 
 /// A synthetic event that wraps a web-style [`MouseEvent`](https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent)
 #[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
-#[derive(Clone, Default)]
+#[derive(Clone, Default, PartialEq)]
 /// Data associated with a mouse event
 ///
 /// Do not use the deprecated fields; they may change or become private in the future.

+ 1 - 1
packages/html/src/events/pointer.rs

@@ -2,7 +2,7 @@ use dioxus_core::Event;
 
 pub type PointerEvent = Event<PointerData>;
 #[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
-#[derive(Debug, Clone)]
+#[derive(Debug, Clone, PartialEq)]
 pub struct PointerData {
     // Mouse only
     pub alt_key: bool,

+ 1 - 1
packages/html/src/events/scroll.rs

@@ -2,7 +2,7 @@ use dioxus_core::Event;
 
 pub type ScrollEvent = Event<ScrollData>;
 #[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
-#[derive(Debug, Clone)]
+#[derive(Debug, Clone, PartialEq, Eq)]
 pub struct ScrollData {}
 
 impl_event! {

+ 1 - 1
packages/html/src/events/selection.rs

@@ -2,7 +2,7 @@ use dioxus_core::Event;
 
 pub type SelectionEvent = Event<SelectionData>;
 #[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
-#[derive(Debug, Clone)]
+#[derive(Debug, Clone, PartialEq, Eq)]
 pub struct SelectionData {}
 
 impl_event! [

+ 1 - 1
packages/html/src/events/toggle.rs

@@ -2,7 +2,7 @@ use dioxus_core::Event;
 
 pub type ToggleEvent = Event<ToggleData>;
 #[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
-#[derive(Debug, Clone)]
+#[derive(Debug, Clone, PartialEq, Eq)]
 pub struct ToggleData {}
 
 impl_event! {

+ 1 - 1
packages/html/src/events/touch.rs

@@ -2,7 +2,7 @@ use dioxus_core::Event;
 
 pub type TouchEvent = Event<TouchData>;
 #[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
-#[derive(Debug, Clone)]
+#[derive(Debug, Clone, PartialEq, Eq)]
 pub struct TouchData {
     pub alt_key: bool,
     pub ctrl_key: bool,

+ 1 - 1
packages/html/src/events/transition.rs

@@ -2,7 +2,7 @@ use dioxus_core::Event;
 
 pub type TransitionEvent = Event<TransitionData>;
 #[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
-#[derive(Debug, Clone)]
+#[derive(Debug, Clone, PartialEq)]
 pub struct TransitionData {
     pub property_name: String,
     pub pseudo_element: String,

+ 1 - 1
packages/html/src/events/wheel.rs

@@ -6,7 +6,7 @@ use crate::geometry::{LinesVector, PagesVector, PixelsVector, WheelDelta};
 
 pub type WheelEvent = Event<WheelData>;
 #[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
-#[derive(Clone)]
+#[derive(Clone, PartialEq, Default)]
 pub struct WheelData {
     #[deprecated(since = "0.3.0", note = "use delta() instead")]
     pub delta_mode: u32,

+ 6 - 0
packages/html/src/lib.rs

@@ -22,6 +22,12 @@ mod render_template;
 #[cfg(feature = "wasm-bind")]
 mod web_sys_bind;
 
+#[cfg(feature = "serialize")]
+mod transit;
+
+#[cfg(feature = "serialize")]
+pub use transit::*;
+
 pub use elements::*;
 pub use events::*;
 pub use global_attributes::*;

+ 217 - 0
packages/html/src/transit.rs

@@ -0,0 +1,217 @@
+use std::{any::Any, rc::Rc};
+
+use crate::events::*;
+use dioxus_core::ElementId;
+use serde::{Deserialize, Serialize};
+
+#[derive(Serialize, Debug, Clone, PartialEq)]
+pub struct HtmlEvent {
+    pub element: ElementId,
+    pub name: String,
+    pub bubbles: bool,
+    pub data: EventData,
+}
+
+impl<'de> Deserialize<'de> for HtmlEvent {
+    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
+    where
+        D: serde::Deserializer<'de>,
+    {
+        #[derive(Deserialize, Debug, Clone)]
+        struct Inner {
+            element: ElementId,
+            name: String,
+            bubbles: bool,
+            data: serde_value::Value,
+        }
+
+        let Inner {
+            element,
+            name,
+            bubbles,
+            data,
+        } = Inner::deserialize(deserializer)?;
+
+        Ok(HtmlEvent {
+            data: fun_name(&name, data).unwrap(),
+            element,
+            bubbles,
+            name,
+        })
+    }
+}
+
+fn fun_name(
+    name: &str,
+    data: serde_value::Value,
+) -> Result<EventData, serde_value::DeserializerError> {
+    use EventData::*;
+
+    // a little macro-esque thing to make the code below more readable
+    #[inline]
+    fn de<'de, F>(f: serde_value::Value) -> Result<F, serde_value::DeserializerError>
+    where
+        F: Deserialize<'de>,
+    {
+        F::deserialize(f)
+    }
+
+    let data = match name {
+        // Mouse
+        "click" | "contextmenu" | "dblclick" | "doubleclick" | "mousedown" | "mouseenter"
+        | "mouseleave" | "mousemove" | "mouseout" | "mouseover" | "mouseup" => Mouse(de(data)?),
+
+        // Clipboard
+        "copy" | "cut" | "paste" => Clipboard(de(data)?),
+
+        // Composition
+        "compositionend" | "compositionstart" | "compositionupdate" => Composition(de(data)?),
+
+        // Keyboard
+        "keydown" | "keypress" | "keyup" => Keyboard(de(data)?),
+
+        // Focus
+        "blur" | "focus" | "focusin" | "focusout" => Focus(de(data)?),
+
+        // Form
+        "change" | "input" | "invalid" | "reset" | "submit" => Form(de(data)?),
+
+        // Drag
+        "drag" | "dragend" | "dragenter" | "dragexit" | "dragleave" | "dragover" | "dragstart"
+        | "drop" => Drag(de(data)?),
+
+        // Pointer
+        "pointerlockchange" | "pointerlockerror" | "pointerdown" | "pointermove" | "pointerup"
+        | "pointerover" | "pointerout" | "pointerenter" | "pointerleave" | "gotpointercapture"
+        | "lostpointercapture" => Pointer(de(data)?),
+
+        // Selection
+        "selectstart" | "selectionchange" | "select" => Selection(de(data)?),
+
+        // Touch
+        "touchcancel" | "touchend" | "touchmove" | "touchstart" => Touch(de(data)?),
+
+        // Srcoll
+        "scroll" => Scroll(de(data)?),
+
+        // Wheel
+        "wheel" => Wheel(de(data)?),
+
+        // Media
+        "abort" | "canplay" | "canplaythrough" | "durationchange" | "emptied" | "encrypted"
+        | "ended" | "interruptbegin" | "interruptend" | "loadeddata" | "loadedmetadata"
+        | "loadstart" | "pause" | "play" | "playing" | "progress" | "ratechange" | "seeked"
+        | "seeking" | "stalled" | "suspend" | "timeupdate" | "volumechange" | "waiting"
+        | "error" | "load" | "loadend" | "timeout" => Media(de(data)?),
+
+        // Animation
+        "animationstart" | "animationend" | "animationiteration" => Animation(de(data)?),
+
+        // Transition
+        "transitionend" => Transition(de(data)?),
+
+        // Toggle
+        "toggle" => Toggle(de(data)?),
+
+        // ImageData => "load" | "error";
+        // OtherData => "abort" | "afterprint" | "beforeprint" | "beforeunload" | "hashchange" | "languagechange" | "message" | "offline" | "online" | "pagehide" | "pageshow" | "popstate" | "rejectionhandled" | "storage" | "unhandledrejection" | "unload" | "userproximity" | "vrdisplayactivate" | "vrdisplayblur" | "vrdisplayconnect" | "vrdisplaydeactivate" | "vrdisplaydisconnect" | "vrdisplayfocus" | "vrdisplaypointerrestricted" | "vrdisplaypointerunrestricted" | "vrdisplaypresentchange";
+        other => {
+            return Err(serde_value::DeserializerError::UnknownVariant(
+                other.to_string(),
+                &[],
+            ))
+        }
+    };
+
+    Ok(data)
+}
+
+impl HtmlEvent {
+    pub fn bubbles(&self) -> bool {
+        event_bubbles(&self.name)
+    }
+}
+
+#[derive(Deserialize, Serialize, Debug, Clone, PartialEq)]
+#[serde(untagged)]
+pub enum EventData {
+    Mouse(MouseData),
+    Clipboard(ClipboardData),
+    Composition(CompositionData),
+    Keyboard(KeyboardData),
+    Focus(FocusData),
+    Form(FormData),
+    Drag(DragData),
+    Pointer(PointerData),
+    Selection(SelectionData),
+    Touch(TouchData),
+    Scroll(ScrollData),
+    Wheel(WheelData),
+    Media(MediaData),
+    Animation(AnimationData),
+    Transition(TransitionData),
+    Toggle(ToggleData),
+}
+
+impl EventData {
+    pub fn into_any(self) -> Rc<dyn Any> {
+        match self {
+            EventData::Mouse(data) => Rc::new(data) as Rc<dyn Any>,
+            EventData::Clipboard(data) => Rc::new(data) as Rc<dyn Any>,
+            EventData::Composition(data) => Rc::new(data) as Rc<dyn Any>,
+            EventData::Keyboard(data) => Rc::new(data) as Rc<dyn Any>,
+            EventData::Focus(data) => Rc::new(data) as Rc<dyn Any>,
+            EventData::Form(data) => Rc::new(data) as Rc<dyn Any>,
+            EventData::Drag(data) => Rc::new(data) as Rc<dyn Any>,
+            EventData::Pointer(data) => Rc::new(data) as Rc<dyn Any>,
+            EventData::Selection(data) => Rc::new(data) as Rc<dyn Any>,
+            EventData::Touch(data) => Rc::new(data) as Rc<dyn Any>,
+            EventData::Scroll(data) => Rc::new(data) as Rc<dyn Any>,
+            EventData::Wheel(data) => Rc::new(data) as Rc<dyn Any>,
+            EventData::Media(data) => Rc::new(data) as Rc<dyn Any>,
+            EventData::Animation(data) => Rc::new(data) as Rc<dyn Any>,
+            EventData::Transition(data) => Rc::new(data) as Rc<dyn Any>,
+            EventData::Toggle(data) => Rc::new(data) as Rc<dyn Any>,
+        }
+    }
+}
+
+#[test]
+fn test_back_and_forth() {
+    let data = HtmlEvent {
+        element: ElementId(0),
+        data: EventData::Mouse(MouseData::default()),
+        name: "click".to_string(),
+        bubbles: true,
+    };
+
+    println!("{}", serde_json::to_string_pretty(&data).unwrap());
+
+    let o = r#"
+{
+  "element": 0,
+  "name": "click",
+  "bubbles": true,
+  "data": {
+    "alt_key": false,
+    "button": 0,
+    "buttons": 0,
+    "client_x": 0,
+    "client_y": 0,
+    "ctrl_key": false,
+    "meta_key": false,
+    "offset_x": 0,
+    "offset_y": 0,
+    "page_x": 0,
+    "page_y": 0,
+    "screen_x": 0,
+    "screen_y": 0,
+    "shift_key": false
+  }
+}
+    "#;
+
+    let p: HtmlEvent = serde_json::from_str(o).unwrap();
+
+    assert_eq!(data, p);
+}

+ 7 - 11
packages/interpreter/src/interpreter.js

@@ -1,11 +1,3 @@
-export function main(rootname = "main") {
-  let root = window.document.getElementById(rootname);
-  if (root != null) {
-    window.interpreter = new Interpreter(root);
-    window.ipc.postMessage(serializeIpcMessage("initialize"));
-  }
-}
-
 class ListenerMap {
   constructor(root) {
     // bubbling events can listen at the root element
@@ -60,7 +52,7 @@ class ListenerMap {
   }
 }
 
-export class Interpreter {
+class Interpreter {
   constructor(root) {
     this.root = root;
     this.listeners = new ListenerMap(root);
@@ -352,6 +344,9 @@ export class Interpreter {
         this.RemoveEventListener(edit.id, edit.name);
         break;
       case "NewEventListener":
+
+        let bubbles = event_bubbles(edit.name);
+
         // this handler is only provided on desktop implementations since this
         // method is not used by the web implementation
         let handler = (event) => {
@@ -438,17 +433,18 @@ export class Interpreter {
                 event: edit.name,
                 mounted_dom_id: parseInt(realId),
                 contents: contents,
+                bubbles,
               })
             );
           }
         };
-        this.NewEventListener(edit.name, edit.id, event_bubbles(edit.name), handler);
+        this.NewEventListener(edit.name, edit.id, bubbles, handler);
         break;
     }
   }
 }
 
-export function serialize_event(event) {
+function serialize_event(event) {
   switch (event.type) {
     case "copy":
     case "cut":