From d06e64e5ad13c03bc085810002b2c3fa8a61ce29 Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Wed, 6 Sep 2023 12:51:02 -0500 Subject: [PATCH] fix dioxus-tui events --- packages/core/tests/miri_full_app.rs | 4 +- packages/dioxus-tui/src/element.rs | 8 +- packages/dioxus-tui/src/events.rs | 108 ++++++++++++++++++++++++ packages/dioxus-tui/src/lib.rs | 14 ++- packages/html/src/events/animation.rs | 11 +++ packages/html/src/events/clipboard.rs | 2 + packages/html/src/events/composition.rs | 8 ++ packages/html/src/events/drag.rs | 7 ++ packages/html/src/events/focus.rs | 7 ++ packages/html/src/events/keyboard.rs | 7 ++ packages/html/src/events/media.rs | 7 ++ packages/html/src/events/scroll.rs | 7 ++ packages/html/src/events/selection.rs | 7 ++ packages/html/src/events/toggle.rs | 7 ++ packages/html/src/events/touch.rs | 7 ++ packages/html/src/events/transition.rs | 7 ++ packages/html/src/events/wheel.rs | 7 ++ packages/rink/examples/widgets.rs | 3 +- packages/rink/src/hooks.rs | 14 +-- 19 files changed, 221 insertions(+), 21 deletions(-) create mode 100644 packages/dioxus-tui/src/events.rs diff --git a/packages/core/tests/miri_full_app.rs b/packages/core/tests/miri_full_app.rs index 8698b01b1..534c3e418 100644 --- a/packages/core/tests/miri_full_app.rs +++ b/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::::default())), ElementId(2), true, ); diff --git a/packages/dioxus-tui/src/element.rs b/packages/dioxus-tui/src/element.rs index ba496fae1..8fdb60b9f 100644 --- a/packages/dioxus-tui/src/element.rs +++ b/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 { // 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, bool)>, + events: &mut Vec<(ElementId, &'static str, Box, bool)>, mount_events: impl Iterator, ) { 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, } diff --git a/packages/dioxus-tui/src/events.rs b/packages/dioxus-tui/src/events.rs new file mode 100644 index 000000000..3e7b6fd2a --- /dev/null +++ b/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::() + .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::().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") + } + } +} diff --git a/packages/dioxus-tui/src/lib.rs b/packages/dioxus-tui/src/lib.rs index fd5b63501..6fafa47ef 100644 --- a/packages/dioxus-tui/src/lib.rs +++ b/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(app: Component, 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>, // Events that are queued up to be sent to the vdom next time the vdom is polled - queued_events: Vec<(ElementId, &'static str, Rc, bool)>, + queued_events: Vec<(ElementId, &'static str, Box, bool)>, #[cfg(all(feature = "hot-reload", debug_assertions))] hot_reload_rx: tokio::sync::mpsc::UnboundedReceiver, } @@ -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 + '_>> { // 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))] diff --git a/packages/html/src/events/animation.rs b/packages/html/src/events/animation.rs index 02612bc77..26db06f9d 100644 --- a/packages/html/src/events/animation.rs +++ b/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(&self) -> Option<&T> { self.inner.as_ref().as_any().downcast_ref::() } diff --git a/packages/html/src/events/clipboard.rs b/packages/html/src/events/clipboard.rs index 0469c4f1c..c0180c728 100644 --- a/packages/html/src/events/clipboard.rs +++ b/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(&self) -> Option<&T> { self.inner.as_ref().as_any().downcast_ref::() } diff --git a/packages/html/src/events/composition.rs b/packages/html/src/events/composition.rs index 18ef4f5d1..4d161436e 100644 --- a/packages/html/src/events/composition.rs +++ b/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() } diff --git a/packages/html/src/events/drag.rs b/packages/html/src/events/drag.rs index 67da07721..3ebd5fdbe 100644 --- a/packages/html/src/events/drag.rs +++ b/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(&self) -> Option<&T> { self.inner.as_any().downcast_ref::() diff --git a/packages/html/src/events/focus.rs b/packages/html/src/events/focus.rs index f96c1eaee..f121feb7b 100644 --- a/packages/html/src/events/focus.rs +++ b/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(&self) -> Option<&T> { self.inner.as_any().downcast_ref::() diff --git a/packages/html/src/events/keyboard.rs b/packages/html/src/events/keyboard.rs index c4c6115c1..a762f7ee9 100644 --- a/packages/html/src/events/keyboard.rs +++ b/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() diff --git a/packages/html/src/events/media.rs b/packages/html/src/events/media.rs index 1abcab21d..7f3180cf7 100644 --- a/packages/html/src/events/media.rs +++ b/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(&self) -> Option<&T> { self.inner.as_any().downcast_ref::() diff --git a/packages/html/src/events/scroll.rs b/packages/html/src/events/scroll.rs index 4655afbcc..3693cc144 100644 --- a/packages/html/src/events/scroll.rs +++ b/packages/html/src/events/scroll.rs @@ -13,6 +13,13 @@ impl From 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(&self) -> Option<&T> { self.inner.as_any().downcast_ref::() diff --git a/packages/html/src/events/selection.rs b/packages/html/src/events/selection.rs index de10b06c4..30c3d9bf0 100644 --- a/packages/html/src/events/selection.rs +++ b/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(&self) -> Option<&T> { self.inner.as_any().downcast_ref::() diff --git a/packages/html/src/events/toggle.rs b/packages/html/src/events/toggle.rs index 7de8be36d..e929a6a64 100644 --- a/packages/html/src/events/toggle.rs +++ b/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(&self) -> Option<&T> { self.inner.as_any().downcast_ref::() diff --git a/packages/html/src/events/touch.rs b/packages/html/src/events/touch.rs index 7e9009ab6..12d8a5de1 100644 --- a/packages/html/src/events/touch.rs +++ b/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() diff --git a/packages/html/src/events/transition.rs b/packages/html/src/events/transition.rs index c6dc65ae1..4e680d650 100644 --- a/packages/html/src/events/transition.rs +++ b/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(&self) -> Option<&T> { self.inner.as_any().downcast_ref::() diff --git a/packages/html/src/events/wheel.rs b/packages/html/src/events/wheel.rs index 157a8dc06..2661eee2b 100644 --- a/packages/html/src/events/wheel.rs +++ b/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 { diff --git a/packages/rink/examples/widgets.rs b/packages/rink/examples/widgets.rs index e1f71fe42..42dc3723d 100644 --- a/packages/rink/examples/widgets.rs +++ b/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::() { + if let Ok(value) = input_event.value().parse::() { self.count = value; } } diff --git a/packages/rink/src/hooks.rs b/packages/rink/src/hooks.rs index 646ae52df..c5378bfbf 100644 --- a/packages/rink/src/hooks.rs +++ b/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>, + pub(crate) values: HashMap>, - pub files: Option, + pub(crate) files: Option, } 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,