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