dioxus_html/events/
mod.rs

1#![doc = include_str!("../../docs/event_handlers.md")]
2
3use std::any::Any;
4use std::sync::RwLock;
5
6macro_rules! impl_event {
7    (
8        $data:ty;
9        $(
10            $( #[$attr:meta] )*
11            $name:ident $(: $js_name:literal)?
12        )*
13    ) => {
14        $(
15            $( #[$attr] )*
16            /// <details open>
17            /// <summary>General Event Handler Information</summary>
18            ///
19            #[doc = include_str!("../../docs/event_handlers.md")]
20            ///
21            /// </details>
22            ///
23            #[doc = include_str!("../../docs/common_event_handler_errors.md")]
24            $(
25                #[doc(alias = $js_name)]
26            )?
27            #[inline]
28            pub fn $name<__Marker>(mut _f: impl ::dioxus_core::prelude::SuperInto<::dioxus_core::prelude::EventHandler<::dioxus_core::Event<$data>>, __Marker>) -> ::dioxus_core::Attribute {
29                // super into will make a closure that is owned by the current owner (either the child component or the parent component).
30                // We can't change that behavior in a minor version because it would cause issues with Components that accept event handlers.
31                // 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.
32                let owner = <::generational_box::UnsyncStorage as ::generational_box::AnyStorage>::owner();
33                let event_handler = ::dioxus_core::prelude::with_owner(owner.clone(), || _f.super_into());
34                ::dioxus_core::Attribute::new(
35                    impl_event!(@name $name $($js_name)?),
36                    ::dioxus_core::AttributeValue::listener(move |e: ::dioxus_core::Event<crate::PlatformEventData>| {
37                        // Force the owner to be moved into the event handler
38                        _ = &owner;
39                        event_handler.call(e.map(|e| e.into()));
40                    }),
41                    None,
42                    false,
43                ).into()
44            }
45
46            #[doc(hidden)]
47            $( #[$attr] )*
48            pub mod $name {
49                use super::*;
50
51                // When expanding the macro, we use this version of the function if we see an inline closure to give better type inference
52                $( #[$attr] )*
53                pub fn call_with_explicit_closure<
54                    __Marker,
55                    Return: ::dioxus_core::SpawnIfAsync<__Marker> + 'static,
56                >(
57                    event_handler: impl FnMut(::dioxus_core::Event<$data>) -> Return + 'static,
58                ) -> ::dioxus_core::Attribute {
59                    #[allow(deprecated)]
60                    super::$name(event_handler)
61                }
62            }
63        )*
64    };
65
66    (@name $name:ident $js_name:literal) => {
67        $js_name
68    };
69    (@name $name:ident) => {
70        stringify!($name)
71    };
72}
73
74static EVENT_CONVERTER: RwLock<Option<Box<dyn HtmlEventConverter>>> = RwLock::new(None);
75
76#[inline]
77pub fn set_event_converter(converter: Box<dyn HtmlEventConverter>) {
78    *EVENT_CONVERTER.write().unwrap() = Some(converter);
79}
80
81#[inline]
82pub(crate) fn with_event_converter<F, R>(f: F) -> R
83where
84    F: FnOnce(&dyn HtmlEventConverter) -> R,
85{
86    let converter = EVENT_CONVERTER.read().unwrap();
87    f(converter.as_ref().unwrap().as_ref())
88}
89
90/// A platform specific event.
91pub struct PlatformEventData {
92    event: Box<dyn Any>,
93}
94
95impl PlatformEventData {
96    pub fn new(event: Box<dyn Any>) -> Self {
97        Self { event }
98    }
99
100    pub fn inner(&self) -> &Box<dyn Any> {
101        &self.event
102    }
103
104    pub fn downcast<T: 'static>(&self) -> Option<&T> {
105        self.event.downcast_ref::<T>()
106    }
107
108    pub fn downcast_mut<T: 'static>(&mut self) -> Option<&mut T> {
109        self.event.downcast_mut::<T>()
110    }
111
112    pub fn into_inner<T: 'static>(self) -> Option<T> {
113        self.event.downcast::<T>().ok().map(|e| *e)
114    }
115}
116
117/// 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.
118pub trait HtmlEventConverter: Send + Sync {
119    /// Convert a general event to an animation data event
120    fn convert_animation_data(&self, event: &PlatformEventData) -> AnimationData;
121    /// Convert a general event to a clipboard data event
122    fn convert_clipboard_data(&self, event: &PlatformEventData) -> ClipboardData;
123    /// Convert a general event to a composition data event
124    fn convert_composition_data(&self, event: &PlatformEventData) -> CompositionData;
125    /// Convert a general event to a drag data event
126    fn convert_drag_data(&self, event: &PlatformEventData) -> DragData;
127    /// Convert a general event to a focus data event
128    fn convert_focus_data(&self, event: &PlatformEventData) -> FocusData;
129    /// Convert a general event to a form data event
130    fn convert_form_data(&self, event: &PlatformEventData) -> FormData;
131    /// Convert a general event to an image data event
132    fn convert_image_data(&self, event: &PlatformEventData) -> ImageData;
133    /// Convert a general event to a keyboard data event
134    fn convert_keyboard_data(&self, event: &PlatformEventData) -> KeyboardData;
135    /// Convert a general event to a media data event
136    fn convert_media_data(&self, event: &PlatformEventData) -> MediaData;
137    /// Convert a general event to a mounted data event
138    fn convert_mounted_data(&self, event: &PlatformEventData) -> MountedData;
139    /// Convert a general event to a mouse data event
140    fn convert_mouse_data(&self, event: &PlatformEventData) -> MouseData;
141    /// Convert a general event to a pointer data event
142    fn convert_pointer_data(&self, event: &PlatformEventData) -> PointerData;
143    /// Convert a general event to a resize data event
144    fn convert_resize_data(&self, event: &PlatformEventData) -> ResizeData;
145    /// Convert a general event to a scroll data event
146    fn convert_scroll_data(&self, event: &PlatformEventData) -> ScrollData;
147    /// Convert a general event to a selection data event
148    fn convert_selection_data(&self, event: &PlatformEventData) -> SelectionData;
149    /// Convert a general event to a toggle data event
150    fn convert_toggle_data(&self, event: &PlatformEventData) -> ToggleData;
151    /// Convert a general event to a touch data event
152    fn convert_touch_data(&self, event: &PlatformEventData) -> TouchData;
153    /// Convert a general event to a transition data event
154    fn convert_transition_data(&self, event: &PlatformEventData) -> TransitionData;
155    /// Convert a general event to a visible data event
156    fn convert_visible_data(&self, event: &PlatformEventData) -> VisibleData;
157    /// Convert a general event to a wheel data event
158    fn convert_wheel_data(&self, event: &PlatformEventData) -> WheelData;
159}
160
161impl From<&PlatformEventData> for AnimationData {
162    fn from(val: &PlatformEventData) -> Self {
163        with_event_converter(|c| c.convert_animation_data(val))
164    }
165}
166
167impl From<&PlatformEventData> for ClipboardData {
168    fn from(val: &PlatformEventData) -> Self {
169        with_event_converter(|c| c.convert_clipboard_data(val))
170    }
171}
172
173impl From<&PlatformEventData> for CompositionData {
174    fn from(val: &PlatformEventData) -> Self {
175        with_event_converter(|c| c.convert_composition_data(val))
176    }
177}
178
179impl From<&PlatformEventData> for DragData {
180    fn from(val: &PlatformEventData) -> Self {
181        with_event_converter(|c| c.convert_drag_data(val))
182    }
183}
184
185impl From<&PlatformEventData> for FocusData {
186    fn from(val: &PlatformEventData) -> Self {
187        with_event_converter(|c| c.convert_focus_data(val))
188    }
189}
190
191impl From<&PlatformEventData> for FormData {
192    fn from(val: &PlatformEventData) -> Self {
193        with_event_converter(|c| c.convert_form_data(val))
194    }
195}
196
197impl From<&PlatformEventData> for ImageData {
198    fn from(val: &PlatformEventData) -> Self {
199        with_event_converter(|c| c.convert_image_data(val))
200    }
201}
202
203impl From<&PlatformEventData> for KeyboardData {
204    fn from(val: &PlatformEventData) -> Self {
205        with_event_converter(|c| c.convert_keyboard_data(val))
206    }
207}
208
209impl From<&PlatformEventData> for MediaData {
210    fn from(val: &PlatformEventData) -> Self {
211        with_event_converter(|c| c.convert_media_data(val))
212    }
213}
214
215impl From<&PlatformEventData> for MountedData {
216    fn from(val: &PlatformEventData) -> Self {
217        with_event_converter(|c| c.convert_mounted_data(val))
218    }
219}
220
221impl From<&PlatformEventData> for MouseData {
222    fn from(val: &PlatformEventData) -> Self {
223        with_event_converter(|c| c.convert_mouse_data(val))
224    }
225}
226
227impl From<&PlatformEventData> for PointerData {
228    fn from(val: &PlatformEventData) -> Self {
229        with_event_converter(|c| c.convert_pointer_data(val))
230    }
231}
232
233impl From<&PlatformEventData> for ResizeData {
234    fn from(val: &PlatformEventData) -> Self {
235        with_event_converter(|c| c.convert_resize_data(val))
236    }
237}
238
239impl From<&PlatformEventData> for ScrollData {
240    fn from(val: &PlatformEventData) -> Self {
241        with_event_converter(|c| c.convert_scroll_data(val))
242    }
243}
244
245impl From<&PlatformEventData> for SelectionData {
246    fn from(val: &PlatformEventData) -> Self {
247        with_event_converter(|c| c.convert_selection_data(val))
248    }
249}
250
251impl From<&PlatformEventData> for ToggleData {
252    fn from(val: &PlatformEventData) -> Self {
253        with_event_converter(|c| c.convert_toggle_data(val))
254    }
255}
256
257impl From<&PlatformEventData> for TouchData {
258    fn from(val: &PlatformEventData) -> Self {
259        with_event_converter(|c| c.convert_touch_data(val))
260    }
261}
262
263impl From<&PlatformEventData> for TransitionData {
264    fn from(val: &PlatformEventData) -> Self {
265        with_event_converter(|c| c.convert_transition_data(val))
266    }
267}
268
269impl From<&PlatformEventData> for VisibleData {
270    fn from(val: &PlatformEventData) -> Self {
271        with_event_converter(|c| c.convert_visible_data(val))
272    }
273}
274
275impl From<&PlatformEventData> for WheelData {
276    fn from(val: &PlatformEventData) -> Self {
277        with_event_converter(|c| c.convert_wheel_data(val))
278    }
279}
280
281mod animation;
282mod clipboard;
283mod composition;
284mod drag;
285mod focus;
286mod form;
287mod image;
288mod keyboard;
289mod media;
290mod mounted;
291mod mouse;
292mod pointer;
293mod resize;
294mod scroll;
295mod selection;
296mod toggle;
297mod touch;
298mod transition;
299mod visible;
300mod wheel;
301
302pub use animation::*;
303pub use clipboard::*;
304pub use composition::*;
305pub use drag::*;
306pub use focus::*;
307pub use form::*;
308pub use image::*;
309pub use keyboard::*;
310pub use media::*;
311pub use mounted::*;
312pub use mouse::*;
313pub use pointer::*;
314pub use resize::*;
315pub use scroll::*;
316pub use selection::*;
317pub use toggle::*;
318pub use touch::*;
319pub use transition::*;
320pub use visible::*;
321pub use wheel::*;