Pārlūkot izejas kodu

fix dioxus-tui events

Evan Almloff 1 gadu atpakaļ
vecāks
revīzija
d06e64e5ad

+ 1 - 3
packages/core/tests/miri_full_app.rs

@@ -14,9 +14,7 @@ fn miri_rollover() {
     for _ in 0..3 {
         dom.handle_event(
             "click",
-            Rc::new(PlatformEventData::new(Box::new(
-                SerializedMouseData::default(),
-            ))),
+            Rc::new(PlatformEventData::new(Box::<SerializedMouseData>::default())),
             ElementId(2),
             true,
         );

+ 4 - 4
packages/dioxus-tui/src/element.rs

@@ -1,7 +1,6 @@
 use std::{
     any::Any,
     fmt::{Display, Formatter},
-    rc::Rc,
 };
 
 use dioxus_core::{ElementId, Mutations, VirtualDom};
@@ -30,7 +29,7 @@ pub(crate) fn find_mount_events(mutations: &Mutations) -> Vec<ElementId> {
 // We need to queue the mounted events to give rink time to rendere and resolve the layout of elements after they are created
 pub(crate) fn create_mounted_events(
     vdom: &VirtualDom,
-    events: &mut Vec<(ElementId, &'static str, Rc<dyn Any>, bool)>,
+    events: &mut Vec<(ElementId, &'static str, Box<dyn Any>, bool)>,
     mount_events: impl Iterator<Item = (ElementId, NodeId)>,
 ) {
     let query: Query = vdom
@@ -42,11 +41,12 @@ pub(crate) fn create_mounted_events(
             query: query.clone(),
             id: node_id,
         };
-        events.push((id, "mounted", Rc::new(MountedData::new(element)), false));
+        events.push((id, "mounted", Box::new(MountedData::new(element)), false));
     }
 }
 
-struct TuiElement {
+#[derive(Clone)]
+pub(crate) struct TuiElement {
     query: Query,
     id: NodeId,
 }

+ 108 - 0
packages/dioxus-tui/src/events.rs

@@ -0,0 +1,108 @@
+use core::panic;
+
+use dioxus_html::*;
+
+use crate::element::TuiElement;
+
+fn downcast(event: &PlatformEventData) -> plasmo::EventData {
+    event
+        .downcast::<plasmo::EventData>()
+        .expect("event should be of type EventData")
+        .clone()
+}
+
+pub(crate) struct SerializedHtmlEventConverter;
+
+impl HtmlEventConverter for SerializedHtmlEventConverter {
+    fn convert_animation_data(&self, _: &PlatformEventData) -> AnimationData {
+        panic!("animation events not supported")
+    }
+
+    fn convert_clipboard_data(&self, _: &PlatformEventData) -> ClipboardData {
+        panic!("clipboard events not supported")
+    }
+
+    fn convert_composition_data(&self, _: &PlatformEventData) -> CompositionData {
+        panic!("composition events not supported")
+    }
+
+    fn convert_drag_data(&self, _: &PlatformEventData) -> DragData {
+        panic!("drag events not supported")
+    }
+
+    fn convert_focus_data(&self, event: &PlatformEventData) -> FocusData {
+        if let plasmo::EventData::Focus(event) = downcast(event) {
+            FocusData::new(event)
+        } else {
+            panic!("event should be of type Focus")
+        }
+    }
+
+    fn convert_form_data(&self, event: &PlatformEventData) -> FormData {
+        if let plasmo::EventData::Form(event) = downcast(event) {
+            FormData::new(event)
+        } else {
+            panic!("event should be of type Form")
+        }
+    }
+
+    fn convert_image_data(&self, _: &PlatformEventData) -> ImageData {
+        panic!("image events not supported")
+    }
+
+    fn convert_keyboard_data(&self, event: &PlatformEventData) -> KeyboardData {
+        if let plasmo::EventData::Keyboard(event) = downcast(event) {
+            KeyboardData::new(event)
+        } else {
+            panic!("event should be of type Keyboard")
+        }
+    }
+
+    fn convert_media_data(&self, _: &PlatformEventData) -> MediaData {
+        panic!("media events not supported")
+    }
+
+    fn convert_mounted_data(&self, event: &PlatformEventData) -> MountedData {
+        event.downcast::<TuiElement>().cloned().unwrap().into()
+    }
+
+    fn convert_mouse_data(&self, event: &PlatformEventData) -> MouseData {
+        if let plasmo::EventData::Mouse(event) = downcast(event) {
+            MouseData::new(event)
+        } else {
+            panic!("event should be of type Mouse")
+        }
+    }
+
+    fn convert_pointer_data(&self, _: &PlatformEventData) -> PointerData {
+        panic!("pointer events not supported")
+    }
+
+    fn convert_scroll_data(&self, _: &PlatformEventData) -> ScrollData {
+        panic!("scroll events not supported")
+    }
+
+    fn convert_selection_data(&self, _: &PlatformEventData) -> SelectionData {
+        panic!("selection events not supported")
+    }
+
+    fn convert_toggle_data(&self, _: &PlatformEventData) -> ToggleData {
+        panic!("toggle events not supported")
+    }
+
+    fn convert_touch_data(&self, _: &PlatformEventData) -> TouchData {
+        panic!("touch events not supported")
+    }
+
+    fn convert_transition_data(&self, _: &PlatformEventData) -> TransitionData {
+        panic!("transition events not supported")
+    }
+
+    fn convert_wheel_data(&self, event: &PlatformEventData) -> WheelData {
+        if let plasmo::EventData::Wheel(event) = downcast(event) {
+            WheelData::new(event)
+        } else {
+            panic!("event should be of type Wheel")
+        }
+    }
+}

+ 11 - 3
packages/dioxus-tui/src/lib.rs

@@ -1,4 +1,5 @@
 mod element;
+mod events;
 
 use std::{
     any::Any,
@@ -8,6 +9,7 @@ use std::{
 };
 
 use dioxus_core::{Component, ElementId, VirtualDom};
+use dioxus_html::PlatformEventData;
 use dioxus_native_core::dioxus::{DioxusState, NodeImmutableDioxusExt};
 use dioxus_native_core::prelude::*;
 
@@ -24,6 +26,8 @@ pub fn launch_cfg(app: Component<()>, cfg: Config) {
 }
 
 pub fn launch_cfg_with_props<Props: 'static>(app: Component<Props>, props: Props, cfg: Config) {
+    dioxus_html::set_event_converter(Box::new(events::SerializedHtmlEventConverter));
+
     render(cfg, |rdom, taffy, event_tx| {
         let dioxus_state = {
             let mut rdom = rdom.write().unwrap();
@@ -81,7 +85,7 @@ struct DioxusRenderer {
     vdom: VirtualDom,
     dioxus_state: Rc<RwLock<DioxusState>>,
     // Events that are queued up to be sent to the vdom next time the vdom is polled
-    queued_events: Vec<(ElementId, &'static str, Rc<dyn Any>, bool)>,
+    queued_events: Vec<(ElementId, &'static str, Box<dyn Any>, bool)>,
     #[cfg(all(feature = "hot-reload", debug_assertions))]
     hot_reload_rx: tokio::sync::mpsc::UnboundedReceiver<dioxus_hot_reload::HotReloadMsg>,
 }
@@ -122,15 +126,19 @@ impl Driver for DioxusRenderer {
         let id = { rdom.read().unwrap().get(id).unwrap().mounted_id() };
         if let Some(id) = id {
             let inner_value = value.deref().clone();
+            let boxed_event = Box::new(inner_value);
+            let platform_event = PlatformEventData::new(boxed_event);
             self.vdom
-                .handle_event(event, inner_value.into_any(), id, bubbles);
+                .handle_event(event, Rc::new(platform_event), id, bubbles);
         }
     }
 
     fn poll_async(&mut self) -> std::pin::Pin<Box<dyn futures::Future<Output = ()> + '_>> {
         // Add any queued events
         for (id, event, value, bubbles) in self.queued_events.drain(..) {
-            self.vdom.handle_event(event, value, id, bubbles);
+            let platform_event = PlatformEventData::new(value);
+            self.vdom
+                .handle_event(event, Rc::new(platform_event), id, bubbles);
         }
 
         #[cfg(all(feature = "hot-reload", debug_assertions))]

+ 11 - 0
packages/html/src/events/animation.rs

@@ -7,18 +7,29 @@ pub struct AnimationData {
 }
 
 impl AnimationData {
+    /// Create a new AnimationData
+    pub fn new(inner: impl HasAnimationData + 'static) -> Self {
+        Self {
+            inner: Box::new(inner),
+        }
+    }
+
+    /// The name of the animation
     pub fn animation_name(&self) -> String {
         self.inner.animation_name()
     }
 
+    /// The name of the pseudo-element the animation runs on
     pub fn pseudo_element(&self) -> String {
         self.inner.pseudo_element()
     }
 
+    /// The amount of time the animation has been running
     pub fn elapsed_time(&self) -> f32 {
         self.inner.elapsed_time()
     }
 
+    /// Downcast this event to a concrete event type
     pub fn downcast<T: 'static>(&self) -> Option<&T> {
         self.inner.as_ref().as_any().downcast_ref::<T>()
     }

+ 2 - 0
packages/html/src/events/clipboard.rs

@@ -25,12 +25,14 @@ impl PartialEq for ClipboardData {
 }
 
 impl ClipboardData {
+    /// Create a new ClipboardData
     pub fn new(inner: impl HasClipboardData) -> Self {
         Self {
             inner: Box::new(inner),
         }
     }
 
+    /// Downcast this event to a concrete event type
     pub fn downcast<T: 'static>(&self) -> Option<&T> {
         self.inner.as_ref().as_any().downcast_ref::<T>()
     }

+ 8 - 0
packages/html/src/events/composition.rs

@@ -27,6 +27,14 @@ impl PartialEq for CompositionData {
 }
 
 impl CompositionData {
+    /// Create a new CompositionData
+    pub fn new(inner: impl HasCompositionData + 'static) -> Self {
+        Self {
+            inner: Box::new(inner),
+        }
+    }
+
+    /// The characters generated by the input method that raised the event
     pub fn data(&self) -> String {
         self.inner.data()
     }

+ 7 - 0
packages/html/src/events/drag.rs

@@ -44,6 +44,13 @@ impl PartialEq for DragData {
 }
 
 impl DragData {
+    /// Create a new DragData
+    pub fn new(inner: impl HasDragData + 'static) -> Self {
+        Self {
+            inner: Box::new(inner),
+        }
+    }
+
     /// Downcast this event data to a specific type
     pub fn downcast<T: 'static>(&self) -> Option<&T> {
         self.inner.as_any().downcast_ref::<T>()

+ 7 - 0
packages/html/src/events/focus.rs

@@ -25,6 +25,13 @@ impl PartialEq for FocusData {
 }
 
 impl FocusData {
+    /// Create a new FocusData
+    pub fn new(inner: impl HasFocusData + 'static) -> Self {
+        Self {
+            inner: Box::new(inner),
+        }
+    }
+
     /// Downcast this event data to a specific type
     pub fn downcast<T: 'static>(&self) -> Option<&T> {
         self.inner.as_any().downcast_ref::<T>()

+ 7 - 0
packages/html/src/events/keyboard.rs

@@ -46,6 +46,13 @@ impl PartialEq for KeyboardData {
 }
 
 impl KeyboardData {
+    /// Create a new KeyboardData
+    pub fn new(inner: impl HasKeyboardData + 'static) -> Self {
+        Self {
+            inner: Box::new(inner),
+        }
+    }
+
     /// The value of the key pressed by the user, taking into consideration the state of modifier keys such as Shift as well as the keyboard locale and layout.
     pub fn key(&self) -> Key {
         self.inner.key()

+ 7 - 0
packages/html/src/events/media.rs

@@ -24,6 +24,13 @@ impl PartialEq for MediaData {
 }
 
 impl MediaData {
+    /// Create a new MediaData
+    pub fn new(inner: impl HasMediaData + 'static) -> Self {
+        Self {
+            inner: Box::new(inner),
+        }
+    }
+
     /// Downcast this event to a concrete event type
     pub fn downcast<T: 'static>(&self) -> Option<&T> {
         self.inner.as_any().downcast_ref::<T>()

+ 7 - 0
packages/html/src/events/scroll.rs

@@ -13,6 +13,13 @@ impl<E: HasScrollData> From<E> for ScrollData {
 }
 
 impl ScrollData {
+    /// Create a new ScrollData
+    pub fn new(inner: impl HasScrollData + 'static) -> Self {
+        Self {
+            inner: Box::new(inner),
+        }
+    }
+
     /// Downcast this event to a concrete event type
     pub fn downcast<T: 'static>(&self) -> Option<&T> {
         self.inner.as_any().downcast_ref::<T>()

+ 7 - 0
packages/html/src/events/selection.rs

@@ -7,6 +7,13 @@ pub struct SelectionData {
 }
 
 impl SelectionData {
+    /// Create a new SelectionData
+    pub fn new(inner: impl HasSelectionData + 'static) -> Self {
+        Self {
+            inner: Box::new(inner),
+        }
+    }
+
     /// Downcast this event to a concrete event type
     pub fn downcast<T: 'static>(&self) -> Option<&T> {
         self.inner.as_any().downcast_ref::<T>()

+ 7 - 0
packages/html/src/events/toggle.rs

@@ -25,6 +25,13 @@ impl PartialEq for ToggleData {
 }
 
 impl ToggleData {
+    /// Create a new ToggleData
+    pub fn new(inner: impl HasToggleData + 'static) -> Self {
+        Self {
+            inner: Box::new(inner),
+        }
+    }
+
     /// Downcast this event to a concrete event type
     pub fn downcast<T: 'static>(&self) -> Option<&T> {
         self.inner.as_any().downcast_ref::<T>()

+ 7 - 0
packages/html/src/events/touch.rs

@@ -32,6 +32,13 @@ impl PartialEq for TouchData {
 }
 
 impl TouchData {
+    /// Create a new TouchData
+    pub fn new(inner: impl HasTouchData + 'static) -> Self {
+        Self {
+            inner: Box::new(inner),
+        }
+    }
+
     /// Returns true if the "ALT" key was down when the touch event was fired.
     pub fn alt_key(&self) -> bool {
         self.inner.alt_key()

+ 7 - 0
packages/html/src/events/transition.rs

@@ -31,6 +31,13 @@ impl PartialEq for TransitionData {
 }
 
 impl TransitionData {
+    /// Create a new TransitionData
+    pub fn new(inner: impl HasTransitionData + 'static) -> Self {
+        Self {
+            inner: Box::new(inner),
+        }
+    }
+
     /// Downcast this event to a concrete event type
     pub fn downcast<T: 'static>(&self) -> Option<&T> {
         self.inner.as_any().downcast_ref::<T>()

+ 7 - 0
packages/html/src/events/wheel.rs

@@ -30,6 +30,13 @@ impl PartialEq for WheelData {
 }
 
 impl WheelData {
+    /// Create a new WheelData
+    pub fn new(inner: impl HasWheelData + 'static) -> Self {
+        Self {
+            inner: Box::new(inner),
+        }
+    }
+
     /// The amount of wheel movement
     #[allow(deprecated)]
     pub fn delta(&self) -> WheelDelta {

+ 2 - 1
packages/rink/examples/widgets.rs

@@ -1,3 +1,4 @@
+use dioxus_html::HasFormData;
 use dioxus_native_core::{
     prelude::*,
     real_dom::{NodeImmutable, NodeTypeMut},
@@ -79,7 +80,7 @@ impl Driver for Counter {
         if event_type == "input" {
             // when the button is clicked, increment the counter
             if let EventData::Form(input_event) = &*event {
-                if let Ok(value) = input_event.value.parse::<f64>() {
+                if let Ok(value) = input_event.value().parse::<f64>() {
                     self.count = value;
                 }
             }

+ 4 - 10
packages/rink/src/hooks.rs

@@ -57,18 +57,18 @@ impl EventData {
             EventData::Keyboard(k) => Rc::new(k),
             EventData::Focus(f) => Rc::new(f),
             EventData::Wheel(w) => Rc::new(w),
-            EventData::Form(f) => Rc::new(f.into_html()),
+            EventData::Form(f) => Rc::new(f),
         }
     }
 }
 
 #[derive(Clone, Debug, PartialEq)]
 pub struct FormData {
-    pub value: String,
+    pub(crate) value: String,
 
-    pub values: HashMap<String, Vec<String>>,
+    pub(crate) values: HashMap<String, Vec<String>>,
 
-    pub files: Option<Files>,
+    pub(crate) files: Option<Files>,
 }
 
 impl HasFormData for FormData {
@@ -85,12 +85,6 @@ impl HasFormData for FormData {
     }
 }
 
-impl FormData {
-    fn into_html(self) -> dioxus_html::FormData {
-        dioxus_html::FormData::new(self)
-    }
-}
-
 #[derive(Clone, Debug, PartialEq)]
 pub struct Files {
     files: FxHashMap<String, File>,