#![doc = include_str!("../../docs/event_handlers.md")] use std::any::Any; use std::sync::RwLock; macro_rules! impl_event { ( $data:ty; $( $( #[$attr:meta] )* $name:ident $(: $js_name:literal)? )* ) => { $( $( #[$attr] )* ///
/// General Event Handler Information /// #[doc = include_str!("../../docs/event_handlers.md")] /// ///
/// #[doc = include_str!("../../docs/common_event_handler_errors.md")] $( #[doc(alias = $js_name)] )? #[inline] pub fn $name<__Marker>(mut _f: impl ::dioxus_core::prelude::SuperInto<::dioxus_core::prelude::EventHandler<::dioxus_core::Event<$data>>, __Marker>) -> ::dioxus_core::Attribute { // super into will make a closure that is owned by the current owner (either the child component or the parent component). // We can't change that behavior in a minor version because it would cause issues with Components that accept event handlers. // Instead we run super into with an owner that is moved into the listener closure so it will be dropped when the closure is dropped. let owner = <::generational_box::UnsyncStorage as ::generational_box::AnyStorage>::owner(); let event_handler = ::dioxus_core::prelude::with_owner(owner.clone(), || _f.super_into()); ::dioxus_core::Attribute::new( impl_event!(@name $name $($js_name)?), ::dioxus_core::AttributeValue::listener(move |e: ::dioxus_core::Event| { // Force the owner to be moved into the event handler _ = &owner; event_handler.call(e.map(|e| e.into())); }), None, false, ).into() } #[doc(hidden)] $( #[$attr] )* pub mod $name { use super::*; // When expanding the macro, we use this version of the function if we see an inline closure to give better type inference $( #[$attr] )* pub fn call_with_explicit_closure< __Marker, Return: ::dioxus_core::SpawnIfAsync<__Marker> + 'static, >( event_handler: impl FnMut(::dioxus_core::Event<$data>) -> Return + 'static, ) -> ::dioxus_core::Attribute { #[allow(deprecated)] super::$name(event_handler) } } )* }; (@name $name:ident $js_name:literal) => { $js_name }; (@name $name:ident) => { stringify!($name) }; } static EVENT_CONVERTER: RwLock>> = RwLock::new(None); #[inline] pub fn set_event_converter(converter: Box) { *EVENT_CONVERTER.write().unwrap() = Some(converter); } #[inline] pub(crate) fn with_event_converter(f: F) -> R where F: FnOnce(&dyn HtmlEventConverter) -> R, { let converter = EVENT_CONVERTER.read().unwrap(); f(converter.as_ref().unwrap().as_ref()) } /// A platform specific event. pub struct PlatformEventData { event: Box, } impl PlatformEventData { pub fn new(event: Box) -> Self { Self { event } } pub fn inner(&self) -> &Box { &self.event } pub fn downcast(&self) -> Option<&T> { self.event.downcast_ref::() } pub fn downcast_mut(&mut self) -> Option<&mut T> { self.event.downcast_mut::() } pub fn into_inner(self) -> Option { self.event.downcast::().ok().map(|e| *e) } } /// A converter between a platform specific event and a general event. All code in a renderer that has a large binary size should be placed in this trait. Each of these functions should be snipped in high levels of optimization. pub trait HtmlEventConverter: Send + Sync { /// Convert a general event to an animation data event fn convert_animation_data(&self, event: &PlatformEventData) -> AnimationData; /// Convert a general event to a clipboard data event fn convert_clipboard_data(&self, event: &PlatformEventData) -> ClipboardData; /// Convert a general event to a composition data event fn convert_composition_data(&self, event: &PlatformEventData) -> CompositionData; /// Convert a general event to a drag data event fn convert_drag_data(&self, event: &PlatformEventData) -> DragData; /// Convert a general event to a focus data event fn convert_focus_data(&self, event: &PlatformEventData) -> FocusData; /// Convert a general event to a form data event fn convert_form_data(&self, event: &PlatformEventData) -> FormData; /// Convert a general event to an image data event fn convert_image_data(&self, event: &PlatformEventData) -> ImageData; /// Convert a general event to a keyboard data event fn convert_keyboard_data(&self, event: &PlatformEventData) -> KeyboardData; /// Convert a general event to a media data event fn convert_media_data(&self, event: &PlatformEventData) -> MediaData; /// Convert a general event to a mounted data event fn convert_mounted_data(&self, event: &PlatformEventData) -> MountedData; /// Convert a general event to a mouse data event fn convert_mouse_data(&self, event: &PlatformEventData) -> MouseData; /// Convert a general event to a pointer data event fn convert_pointer_data(&self, event: &PlatformEventData) -> PointerData; /// Convert a general event to a resize data event fn convert_resize_data(&self, event: &PlatformEventData) -> ResizeData; /// Convert a general event to a scroll data event fn convert_scroll_data(&self, event: &PlatformEventData) -> ScrollData; /// Convert a general event to a selection data event fn convert_selection_data(&self, event: &PlatformEventData) -> SelectionData; /// Convert a general event to a toggle data event fn convert_toggle_data(&self, event: &PlatformEventData) -> ToggleData; /// Convert a general event to a touch data event fn convert_touch_data(&self, event: &PlatformEventData) -> TouchData; /// Convert a general event to a transition data event fn convert_transition_data(&self, event: &PlatformEventData) -> TransitionData; /// Convert a general event to a visible data event fn convert_visible_data(&self, event: &PlatformEventData) -> VisibleData; /// Convert a general event to a wheel data event fn convert_wheel_data(&self, event: &PlatformEventData) -> WheelData; } impl From<&PlatformEventData> for AnimationData { fn from(val: &PlatformEventData) -> Self { with_event_converter(|c| c.convert_animation_data(val)) } } impl From<&PlatformEventData> for ClipboardData { fn from(val: &PlatformEventData) -> Self { with_event_converter(|c| c.convert_clipboard_data(val)) } } impl From<&PlatformEventData> for CompositionData { fn from(val: &PlatformEventData) -> Self { with_event_converter(|c| c.convert_composition_data(val)) } } impl From<&PlatformEventData> for DragData { fn from(val: &PlatformEventData) -> Self { with_event_converter(|c| c.convert_drag_data(val)) } } impl From<&PlatformEventData> for FocusData { fn from(val: &PlatformEventData) -> Self { with_event_converter(|c| c.convert_focus_data(val)) } } impl From<&PlatformEventData> for FormData { fn from(val: &PlatformEventData) -> Self { with_event_converter(|c| c.convert_form_data(val)) } } impl From<&PlatformEventData> for ImageData { fn from(val: &PlatformEventData) -> Self { with_event_converter(|c| c.convert_image_data(val)) } } impl From<&PlatformEventData> for KeyboardData { fn from(val: &PlatformEventData) -> Self { with_event_converter(|c| c.convert_keyboard_data(val)) } } impl From<&PlatformEventData> for MediaData { fn from(val: &PlatformEventData) -> Self { with_event_converter(|c| c.convert_media_data(val)) } } impl From<&PlatformEventData> for MountedData { fn from(val: &PlatformEventData) -> Self { with_event_converter(|c| c.convert_mounted_data(val)) } } impl From<&PlatformEventData> for MouseData { fn from(val: &PlatformEventData) -> Self { with_event_converter(|c| c.convert_mouse_data(val)) } } impl From<&PlatformEventData> for PointerData { fn from(val: &PlatformEventData) -> Self { with_event_converter(|c| c.convert_pointer_data(val)) } } impl From<&PlatformEventData> for ResizeData { fn from(val: &PlatformEventData) -> Self { with_event_converter(|c| c.convert_resize_data(val)) } } impl From<&PlatformEventData> for ScrollData { fn from(val: &PlatformEventData) -> Self { with_event_converter(|c| c.convert_scroll_data(val)) } } impl From<&PlatformEventData> for SelectionData { fn from(val: &PlatformEventData) -> Self { with_event_converter(|c| c.convert_selection_data(val)) } } impl From<&PlatformEventData> for ToggleData { fn from(val: &PlatformEventData) -> Self { with_event_converter(|c| c.convert_toggle_data(val)) } } impl From<&PlatformEventData> for TouchData { fn from(val: &PlatformEventData) -> Self { with_event_converter(|c| c.convert_touch_data(val)) } } impl From<&PlatformEventData> for TransitionData { fn from(val: &PlatformEventData) -> Self { with_event_converter(|c| c.convert_transition_data(val)) } } impl From<&PlatformEventData> for VisibleData { fn from(val: &PlatformEventData) -> Self { with_event_converter(|c| c.convert_visible_data(val)) } } impl From<&PlatformEventData> for WheelData { fn from(val: &PlatformEventData) -> Self { with_event_converter(|c| c.convert_wheel_data(val)) } } mod animation; mod clipboard; mod composition; mod drag; mod focus; mod form; mod image; mod keyboard; mod media; mod mounted; mod mouse; mod pointer; mod resize; mod scroll; mod selection; mod toggle; mod touch; mod transition; mod visible; mod wheel; pub use animation::*; pub use clipboard::*; pub use composition::*; pub use drag::*; pub use focus::*; pub use form::*; pub use image::*; pub use keyboard::*; pub use media::*; pub use mounted::*; pub use mouse::*; pub use pointer::*; pub use resize::*; pub use scroll::*; pub use selection::*; pub use toggle::*; pub use touch::*; pub use transition::*; pub use visible::*; pub use wheel::*;