1use dioxus_html::{
2 DragData, FormData, HtmlEventConverter, ImageData, MountedData, PlatformEventData,
3};
4use form::WebFormData;
5use load::WebImageEvent;
6use wasm_bindgen::JsCast;
7use web_sys::{Document, Element, Event};
8
9mod animation;
10mod cancel;
11mod clipboard;
12mod composition;
13mod drag;
14mod file;
15mod focus;
16mod form;
17mod keyboard;
18mod load;
19mod media;
20#[cfg(feature = "mounted")]
21mod mounted;
22mod mouse;
23mod pointer;
24mod resize;
25mod scroll;
26mod selection;
27mod toggle;
28mod touch;
29mod transition;
30mod visible;
31mod wheel;
32
33pub(crate) struct Synthetic<T: 'static> {
35 pub event: T,
37}
38
39impl<T: 'static> Synthetic<T> {
40 pub fn new(event: T) -> Self {
42 Self { event }
43 }
44}
45
46pub(crate) struct WebEventConverter;
47
48#[inline(always)]
49fn downcast_event(event: &dioxus_html::PlatformEventData) -> &GenericWebSysEvent {
50 event
51 .downcast::<GenericWebSysEvent>()
52 .expect("event should be a GenericWebSysEvent")
53}
54
55impl HtmlEventConverter for WebEventConverter {
56 #[inline(always)]
57 fn convert_animation_data(
58 &self,
59 event: &dioxus_html::PlatformEventData,
60 ) -> dioxus_html::AnimationData {
61 Synthetic::<web_sys::AnimationEvent>::from(downcast_event(event).raw.clone()).into()
62 }
63
64 #[inline(always)]
65 fn convert_cancel_data(
66 &self,
67 event: &dioxus_html::PlatformEventData,
68 ) -> dioxus_html::CancelData {
69 Synthetic::new(downcast_event(event).raw.clone()).into()
70 }
71
72 #[inline(always)]
73 fn convert_clipboard_data(
74 &self,
75 event: &dioxus_html::PlatformEventData,
76 ) -> dioxus_html::ClipboardData {
77 Synthetic::new(downcast_event(event).raw.clone()).into()
78 }
79
80 #[inline(always)]
81 fn convert_composition_data(
82 &self,
83 event: &dioxus_html::PlatformEventData,
84 ) -> dioxus_html::CompositionData {
85 Synthetic::<web_sys::CompositionEvent>::from(downcast_event(event).raw.clone()).into()
86 }
87
88 #[inline(always)]
89 fn convert_drag_data(&self, event: &dioxus_html::PlatformEventData) -> dioxus_html::DragData {
90 let event = downcast_event(event);
91 DragData::new(Synthetic::new(
92 event.raw.clone().unchecked_into::<web_sys::DragEvent>(),
93 ))
94 }
95
96 #[inline(always)]
97 fn convert_focus_data(&self, event: &dioxus_html::PlatformEventData) -> dioxus_html::FocusData {
98 Synthetic::<web_sys::FocusEvent>::from(downcast_event(event).raw.clone()).into()
99 }
100
101 #[inline(always)]
102 fn convert_form_data(&self, event: &dioxus_html::PlatformEventData) -> dioxus_html::FormData {
103 let event = downcast_event(event);
104 FormData::new(WebFormData::new(event.element.clone(), event.raw.clone()))
105 }
106
107 #[inline(always)]
108 fn convert_image_data(&self, event: &dioxus_html::PlatformEventData) -> dioxus_html::ImageData {
109 let event = downcast_event(event);
110 let error = event.raw.type_() == "error";
111 ImageData::new(WebImageEvent::new(event.raw.clone(), error))
112 }
113
114 #[inline(always)]
115 fn convert_keyboard_data(
116 &self,
117 event: &dioxus_html::PlatformEventData,
118 ) -> dioxus_html::KeyboardData {
119 Synthetic::<web_sys::KeyboardEvent>::from(downcast_event(event).raw.clone()).into()
120 }
121
122 #[inline(always)]
123 fn convert_media_data(&self, event: &dioxus_html::PlatformEventData) -> dioxus_html::MediaData {
124 Synthetic::new(downcast_event(event).raw.clone()).into()
125 }
126
127 #[allow(unused_variables)]
128 #[inline(always)]
129 fn convert_mounted_data(&self, event: &dioxus_html::PlatformEventData) -> MountedData {
130 #[cfg(feature = "mounted")]
131 {
132 Synthetic::new(
133 event
134 .downcast::<web_sys::Element>()
135 .expect("event should be a web_sys::Element")
136 .clone(),
137 )
138 .into()
139 }
140 #[cfg(not(feature = "mounted"))]
141 {
142 panic!("mounted events are not supported without the mounted feature on the dioxus-web crate enabled")
143 }
144 }
145
146 #[inline(always)]
147 fn convert_mouse_data(&self, event: &dioxus_html::PlatformEventData) -> dioxus_html::MouseData {
148 Synthetic::<web_sys::MouseEvent>::from(downcast_event(event).raw.clone()).into()
149 }
150
151 #[inline(always)]
152 fn convert_pointer_data(
153 &self,
154 event: &dioxus_html::PlatformEventData,
155 ) -> dioxus_html::PointerData {
156 Synthetic::<web_sys::PointerEvent>::from(downcast_event(event).raw.clone()).into()
157 }
158
159 #[inline(always)]
160 fn convert_resize_data(
161 &self,
162 event: &dioxus_html::PlatformEventData,
163 ) -> dioxus_html::ResizeData {
164 Synthetic::<web_sys::ResizeObserverEntry>::from(downcast_event(event).raw.clone()).into()
165 }
166
167 #[inline(always)]
168 fn convert_scroll_data(
169 &self,
170 event: &dioxus_html::PlatformEventData,
171 ) -> dioxus_html::ScrollData {
172 Synthetic::new(downcast_event(event).raw.clone()).into()
173 }
174
175 #[inline(always)]
176 fn convert_selection_data(
177 &self,
178 event: &dioxus_html::PlatformEventData,
179 ) -> dioxus_html::SelectionData {
180 Synthetic::new(downcast_event(event).raw.clone()).into()
181 }
182
183 #[inline(always)]
184 fn convert_toggle_data(
185 &self,
186 event: &dioxus_html::PlatformEventData,
187 ) -> dioxus_html::ToggleData {
188 Synthetic::new(downcast_event(event).raw.clone()).into()
189 }
190
191 #[inline(always)]
192 fn convert_touch_data(&self, event: &dioxus_html::PlatformEventData) -> dioxus_html::TouchData {
193 Synthetic::<web_sys::TouchEvent>::from(downcast_event(event).raw.clone()).into()
194 }
195
196 #[inline(always)]
197 fn convert_transition_data(
198 &self,
199 event: &dioxus_html::PlatformEventData,
200 ) -> dioxus_html::TransitionData {
201 Synthetic::<web_sys::TransitionEvent>::from(downcast_event(event).raw.clone()).into()
202 }
203
204 #[inline(always)]
205 fn convert_visible_data(
206 &self,
207 event: &dioxus_html::PlatformEventData,
208 ) -> dioxus_html::VisibleData {
209 Synthetic::<web_sys::IntersectionObserverEntry>::from(downcast_event(event).raw.clone())
210 .into()
211 }
212
213 #[inline(always)]
214 fn convert_wheel_data(&self, event: &dioxus_html::PlatformEventData) -> dioxus_html::WheelData {
215 Synthetic::<web_sys::WheelEvent>::from(downcast_event(event).raw.clone()).into()
216 }
217}
218
219pub trait WebEventExt {
221 type WebEvent;
223
224 fn try_as_web_event(&self) -> Option<Self::WebEvent>;
226
227 #[inline(always)]
229 fn as_web_event(&self) -> Self::WebEvent
230 where
231 Self::WebEvent: 'static,
232 {
233 self.try_as_web_event().unwrap_or_else(|| {
234 panic!(
235 "Error downcasting to `web-sys`, event should be a {}.",
236 std::any::type_name::<Self::WebEvent>()
237 )
238 })
239 }
240}
241
242struct GenericWebSysEvent {
243 raw: Event,
244 element: Element,
245}
246
247pub(crate) fn virtual_event_from_websys_event(
250 event: web_sys::Event,
251 target: Element,
252) -> PlatformEventData {
253 PlatformEventData::new(Box::new(GenericWebSysEvent {
254 raw: event,
255 element: target,
256 }))
257}
258
259pub(crate) fn load_document() -> Document {
260 web_sys::window()
261 .expect("should have access to the Window")
262 .document()
263 .expect("should have access to the Document")
264}
265
266macro_rules! uncheck_convert {
267 ($t:ty) => {
268 impl From<Event> for Synthetic<$t> {
269 #[inline]
270 fn from(e: Event) -> Self {
271 let e: $t = e.unchecked_into();
272 Self::new(e)
273 }
274 }
275
276 impl From<&Event> for Synthetic<$t> {
277 #[inline]
278 fn from(e: &Event) -> Self {
279 let e: &$t = e.unchecked_ref();
280 Self::new(e.clone())
281 }
282 }
283 };
284 ($($t:ty),+ $(,)?) => {
285 $(uncheck_convert!($t);)+
286 };
287}
288
289uncheck_convert![
290 web_sys::CompositionEvent,
291 web_sys::KeyboardEvent,
292 web_sys::TouchEvent,
293 web_sys::PointerEvent,
294 web_sys::WheelEvent,
295 web_sys::AnimationEvent,
296 web_sys::TransitionEvent,
297 web_sys::MouseEvent,
298 web_sys::FocusEvent,
299];