From 8d42191d7ac5877bd6858a43dafa1b4c806bf295 Mon Sep 17 00:00:00 2001 From: Aster Date: Sat, 12 Feb 2022 20:57:13 +0800 Subject: [PATCH] Add `From` trait to convert web_sys Events to html Data --- .gitignore | 5 +- packages/html/Cargo.toml | 21 +++ packages/html/src/lib.rs | 2 + packages/html/src/web_sys_bind/events.rs | 161 +++++++++++++++++++++++ packages/html/src/web_sys_bind/mod.rs | 1 + packages/web/Cargo.toml | 2 +- packages/web/src/dom.rs | 97 +------------- 7 files changed, 197 insertions(+), 92 deletions(-) create mode 100644 packages/html/src/web_sys_bind/events.rs create mode 100644 packages/html/src/web_sys_bind/mod.rs diff --git a/.gitignore b/.gitignore index 854f5cb26..e093afe8a 100644 --- a/.gitignore +++ b/.gitignore @@ -8,4 +8,7 @@ Cargo.lock !.vscode/tasks.json !.vscode/launch.json !.vscode/extensions.json -tarpaulin-report.html \ No newline at end of file +tarpaulin-report.html + +# Jetbrain +.idea/ \ No newline at end of file diff --git a/packages/html/Cargo.toml b/packages/html/Cargo.toml index 293d4c465..775fcc015 100644 --- a/packages/html/Cargo.toml +++ b/packages/html/Cargo.toml @@ -14,7 +14,28 @@ keywords = ["dom", "ui", "gui", "react", "wasm"] dioxus-core = { path = "../core", version = "^0.1.9" } serde = { version = "1", features = ["derive"], optional = true } serde_repr = { version = "0.1", optional = true } +wasm-bindgen = { version = "0.2.79", optional = true } + +[dependencies.web-sys] +optional = true +version = "0.3.56" +features = [ + "TouchEvent", + "MouseEvent", + "InputEvent", + "ClipboardEvent", + "KeyboardEvent", + "TouchEvent", + "WheelEvent", + "AnimationEvent", + "TransitionEvent", + "PointerEvent", + "FocusEvent", + "CompositionEvent", + "ClipboardEvent", +] [features] default = [] serialize = ["serde", "serde_repr"] +wasm-bind = ["web-sys", "wasm-bindgen"] \ No newline at end of file diff --git a/packages/html/src/lib.rs b/packages/html/src/lib.rs index 79c00b1fc..1440fd9ae 100644 --- a/packages/html/src/lib.rs +++ b/packages/html/src/lib.rs @@ -16,6 +16,8 @@ mod elements; mod events; mod global_attributes; +#[cfg(feature = "wasm-bind")] +mod web_sys_bind; pub use elements::*; pub use events::*; diff --git a/packages/html/src/web_sys_bind/events.rs b/packages/html/src/web_sys_bind/events.rs new file mode 100644 index 000000000..4b721e45d --- /dev/null +++ b/packages/html/src/web_sys_bind/events.rs @@ -0,0 +1,161 @@ +use crate::on::{ + AnimationData, CompositionData, KeyboardData, MouseData, PointerData, TouchData, + TransitionData, WheelData, +}; +use crate::KeyCode; +use wasm_bindgen::JsCast; +use web_sys::{ + AnimationEvent, CompositionEvent, Event, KeyboardEvent, MouseEvent, PointerEvent, TouchEvent, + TransitionEvent, WheelEvent, +}; + +macro_rules! uncheck_convert { + ($t:ty, $d:ty) => { + impl From for $d { + #[inline] + fn from(e: Event) -> Self { + let e: $t = e.unchecked_into(); + Self::from(&e) + } + } + + impl From<&Event> for $d { + #[inline] + fn from(e: &Event) -> Self { + let e: &$t = e.unchecked_ref(); + Self::from(e) + } + } + }; + ($($t:ty => $d:ty),+ $(,)?) => { + $(uncheck_convert!($t, $d);)+ + }; +} + +uncheck_convert![ + CompositionEvent => CompositionData, + KeyboardEvent => KeyboardData, + MouseEvent => MouseData, + TouchEvent => TouchData, + PointerEvent => PointerData, + WheelEvent => WheelData, + AnimationEvent => AnimationData, + TransitionEvent => TransitionData, +]; + +impl From<&CompositionEvent> for CompositionData { + fn from(e: &CompositionEvent) -> Self { + Self { + data: e.data().unwrap_or_default(), + } + } +} + +impl From<&KeyboardEvent> for KeyboardData { + fn from(e: &KeyboardEvent) -> Self { + Self { + alt_key: e.alt_key(), + char_code: e.char_code(), + key: e.key(), + key_code: KeyCode::from_raw_code(e.key_code() as u8), + ctrl_key: e.ctrl_key(), + locale: "not implemented".to_string(), + location: e.location() as usize, + meta_key: e.meta_key(), + repeat: e.repeat(), + shift_key: e.shift_key(), + which: e.which() as usize, + } + } +} + +impl From<&MouseEvent> for MouseData { + fn from(e: &MouseEvent) -> Self { + Self { + alt_key: e.alt_key(), + button: e.button(), + buttons: e.buttons(), + client_x: e.client_x(), + client_y: e.client_y(), + ctrl_key: e.ctrl_key(), + meta_key: e.meta_key(), + screen_x: e.screen_x(), + screen_y: e.screen_y(), + shift_key: e.shift_key(), + page_x: e.page_x(), + page_y: e.page_y(), + } + } +} + +impl From<&TouchEvent> for TouchData { + fn from(e: &TouchEvent) -> Self { + Self { + alt_key: e.alt_key(), + ctrl_key: e.ctrl_key(), + meta_key: e.meta_key(), + shift_key: e.shift_key(), + } + } +} + +impl From<&PointerEvent> for PointerData { + fn from(e: &PointerEvent) -> Self { + Self { + alt_key: e.alt_key(), + button: e.button(), + buttons: e.buttons(), + client_x: e.client_x(), + client_y: e.client_y(), + ctrl_key: e.ctrl_key(), + meta_key: e.meta_key(), + page_x: e.page_x(), + page_y: e.page_y(), + screen_x: e.screen_x(), + screen_y: e.screen_y(), + shift_key: e.shift_key(), + pointer_id: e.pointer_id(), + width: e.width(), + height: e.height(), + pressure: e.pressure(), + tangential_pressure: e.tangential_pressure(), + tilt_x: e.tilt_x(), + tilt_y: e.tilt_y(), + twist: e.twist(), + pointer_type: e.pointer_type(), + is_primary: e.is_primary(), + // get_modifier_state: evt.get_modifier_state(), + } + } +} + +impl From<&WheelEvent> for WheelData { + fn from(e: &WheelEvent) -> Self { + Self { + delta_x: e.delta_x(), + delta_y: e.delta_y(), + delta_z: e.delta_z(), + delta_mode: e.delta_mode(), + } + } +} + +impl From<&AnimationEvent> for AnimationData { + fn from(e: &AnimationEvent) -> Self { + Self { + elapsed_time: e.elapsed_time(), + animation_name: e.animation_name(), + pseudo_element: e.pseudo_element(), + } + } +} + +impl From<&TransitionEvent> for TransitionData { + fn from(e: &TransitionEvent) -> Self { + Self { + elapsed_time: e.elapsed_time(), + property_name: e.property_name(), + pseudo_element: e.pseudo_element(), + } + } +} diff --git a/packages/html/src/web_sys_bind/mod.rs b/packages/html/src/web_sys_bind/mod.rs new file mode 100644 index 000000000..98277fed2 --- /dev/null +++ b/packages/html/src/web_sys_bind/mod.rs @@ -0,0 +1 @@ +mod events; diff --git a/packages/web/Cargo.toml b/packages/web/Cargo.toml index 7a3baa955..2870640c4 100644 --- a/packages/web/Cargo.toml +++ b/packages/web/Cargo.toml @@ -12,7 +12,7 @@ keywords = ["dom", "ui", "gui", "react", "wasm"] [dependencies] dioxus-core = { path = "../core", version = "^0.1.9" } -dioxus-html = { path = "../html", version = "^0.1.6" } +dioxus-html = { path = "../html", version = "^0.1.6", features = ["wasm-bind"] } js-sys = "0.3.56" wasm-bindgen = { version = "0.2.79", features = ["enable-interning"] } lazy_static = "1.4.0" diff --git a/packages/web/src/dom.rs b/packages/web/src/dom.rs index 48fb25e6e..44f782b62 100644 --- a/packages/web/src/dom.rs +++ b/packages/web/src/dom.rs @@ -170,7 +170,6 @@ fn virtual_event_from_websys_event( target: Element, ) -> Arc { use dioxus_html::on::*; - use dioxus_html::KeyCode; match event.type_().as_str() { "copy" | "cut" | "paste" => Arc::new(ClipboardData {}), @@ -180,22 +179,7 @@ fn virtual_event_from_websys_event( data: evt.data().unwrap_or_default(), }) } - "keydown" | "keypress" | "keyup" => { - let evt: &web_sys::KeyboardEvent = event.dyn_ref().unwrap(); - Arc::new(KeyboardData { - 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, - }) - } + "keydown" | "keypress" | "keyup" => Arc::new(KeyboardData::from(event)), "focus" | "blur" => Arc::new(FocusData {}), // todo: these handlers might get really slow if the input box gets large and allocation pressure is heavy @@ -272,88 +256,21 @@ fn virtual_event_from_websys_event( "click" | "contextmenu" | "doubleclick" | "drag" | "dragend" | "dragenter" | "dragexit" | "dragleave" | "dragover" | "dragstart" | "drop" | "mousedown" | "mouseenter" | "mouseleave" | "mousemove" | "mouseout" | "mouseover" | "mouseup" => { - let evt: &web_sys::MouseEvent = event.dyn_ref().unwrap(); - Arc::new(MouseData { - 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(), - }) + Arc::new(MouseData::from(event)) } "pointerdown" | "pointermove" | "pointerup" | "pointercancel" | "gotpointercapture" | "lostpointercapture" | "pointerenter" | "pointerleave" | "pointerover" | "pointerout" => { - let evt: &web_sys::PointerEvent = event.dyn_ref().unwrap(); - Arc::new(PointerData { - 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(), - }) + Arc::new(PointerData::from(event)) } "select" => Arc::new(SelectionData {}), - "touchcancel" | "touchend" | "touchmove" | "touchstart" => { - let evt: &web_sys::TouchEvent = event.dyn_ref().unwrap(); - Arc::new(TouchData { - alt_key: evt.alt_key(), - ctrl_key: evt.ctrl_key(), - meta_key: evt.meta_key(), - shift_key: evt.shift_key(), - }) - } + "touchcancel" | "touchend" | "touchmove" | "touchstart" => Arc::new(TouchData::from(event)), "scroll" => Arc::new(()), - "wheel" => { - let evt: &web_sys::WheelEvent = event.dyn_ref().unwrap(); - Arc::new(WheelData { - delta_x: evt.delta_x(), - delta_y: evt.delta_y(), - delta_z: evt.delta_z(), - delta_mode: evt.delta_mode(), - }) - } + "wheel" => Arc::new(WheelData::from(event)), "animationstart" | "animationend" | "animationiteration" => { - let evt: &web_sys::AnimationEvent = event.dyn_ref().unwrap(); - Arc::new(AnimationData { - elapsed_time: evt.elapsed_time(), - animation_name: evt.animation_name(), - pseudo_element: evt.pseudo_element(), - }) - } - "transitionend" => { - let evt: &web_sys::TransitionEvent = event.dyn_ref().unwrap(); - Arc::new(TransitionData { - elapsed_time: evt.elapsed_time(), - property_name: evt.property_name(), - pseudo_element: evt.pseudo_element(), - }) + Arc::new(AnimationData::from(event)) } + "transitionend" => Arc::new(TransitionData::from(event)), "abort" | "canplay" | "canplaythrough" | "durationchange" | "emptied" | "encrypted" | "ended" | "error" | "loadeddata" | "loadedmetadata" | "loadstart" | "pause" | "play" | "playing" | "progress" | "ratechange" | "seeked" | "seeking" | "stalled" | "suspend"