1use crate::traits::StaticEvent;
2use wasm_bindgen::JsCast;
3use web_sys::{EventTarget, HtmlInputElement, HtmlTextAreaElement};
4
5#[cfg(feature = "nightly")]
6pub struct Event<const NAME: &'static str, T> {
7 event: T,
8}
9
10#[cfg(feature = "nightly")]
11impl<T, const NAME: &'static str> StaticEvent for Event<NAME, T>
12where
13 T: JsCast,
14{
15 const EVENT_TYPE: &'static str = NAME;
16
17 #[inline]
18 fn unchecked_from_event(event: web_sys::Event) -> Self {
19 Self {
20 event: event.dyn_into().unwrap(),
22 }
23 }
24}
25
26#[cfg(feature = "nightly")]
29impl<T, const NAME: &'static str> Event<NAME, T>
30where
31 T: AsRef<web_sys::Event>,
32{
33 #[inline]
34 pub fn prevent_default(&self) {
35 self.event.as_ref().prevent_default();
36 }
37
38 #[inline]
39 pub fn target(&self) -> Option<EventTarget> {
40 self.event.as_ref().target()
41 }
42
43 #[inline]
44 pub fn dyn_target<A>(&self) -> Option<A>
45 where
46 A: JsCast,
47 {
48 self.target()?.dyn_into().ok()
49 }
50}
51
52macro_rules! make_event {
53 ($name:ident, $type:literal => $event:path) => {
54 #[derive(Debug)]
55 pub struct $name {
56 event: $event,
57 }
58
59 impl StaticEvent for $name {
60 const EVENT_TYPE: &'static str = $type;
61
62 #[inline]
63 fn unchecked_from_event(event: web_sys::Event) -> Self {
64 Self {
65 event: event.unchecked_into(),
66 }
67 }
68 }
69
70 impl $name {
71 #[inline]
72 pub fn prevent_default(&self) {
73 self.event.prevent_default();
74 }
75
76 #[inline]
77 pub fn stop_propagation(&self) {
78 self.event.stop_propagation();
79 }
80
81 #[inline]
82 pub fn stop_immediate_propagation(&self) {
83 self.event.stop_immediate_propagation();
84 }
85
86 #[inline]
87 pub fn target(&self) -> Option<EventTarget> {
88 self.event.target()
89 }
90
91 #[inline]
92 pub fn dyn_target<A>(&self) -> Option<A>
93 where
94 A: JsCast,
95 {
96 self.target()?.dyn_into().ok()
97 }
98 }
99 };
100}
101
102#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
103pub enum MouseButton {
104 Left,
105 Middle,
106 Right,
107 Button4,
108 Button5,
109}
110
111macro_rules! make_mouse_event {
112 ($name:ident, $type:literal => $event:path) => {
113 make_event!($name, $type => $event);
114
115 impl $name {
116 #[inline] pub fn x(&self) -> i32 { self.event.client_x() }
117 #[inline] pub fn y(&self) -> i32 { self.event.client_y() }
118
119 #[inline] pub fn movement_x(&self) -> i32 { self.event.movement_x() }
120 #[inline] pub fn movement_y(&self) -> i32 { self.event.movement_y() }
121
122 #[inline] pub fn offset_x(&self) -> i32 { self.event.offset_x() }
123 #[inline] pub fn offset_y(&self) -> i32 { self.event.offset_y() }
124
125 #[inline] pub fn page_x(&self) -> i32 { self.event.page_x() }
126 #[inline] pub fn page_y(&self) -> i32 { self.event.page_y() }
127
128 #[inline] pub fn screen_x(&self) -> i32 { self.event.screen_x() }
129 #[inline] pub fn screen_y(&self) -> i32 { self.event.screen_y() }
130
131 #[inline] pub fn ctrl_key(&self) -> bool { self.event.ctrl_key() || self.event.meta_key() }
132 #[inline] pub fn shift_key(&self) -> bool { self.event.shift_key() }
133 #[inline] pub fn alt_key(&self) -> bool { self.event.alt_key() }
134
135 #[inline] pub fn mouse_x(&self) -> i32 { self.event.client_x() }
137 #[inline] pub fn mouse_y(&self) -> i32 { self.event.client_y() }
138
139 pub fn button(&self) -> MouseButton {
140 match self.event.button() {
141 0 => MouseButton::Left,
142 1 => MouseButton::Middle,
143 2 => MouseButton::Right,
144 3 => MouseButton::Button4,
145 4 => MouseButton::Button5,
146 _ => unreachable!("Unexpected MouseEvent.button value"),
147 }
148 }
149 }
150 };
151}
152
153macro_rules! make_keyboard_event {
154 ($name:ident, $type:literal) => {
155 make_event!($name, $type => web_sys::KeyboardEvent);
156
157 impl $name {
158 #[inline] pub fn key(&self) -> String { self.event.key() }
160
161 #[inline] pub fn ctrl_key(&self) -> bool { self.event.ctrl_key() || self.event.meta_key() }
162 #[inline] pub fn shift_key(&self) -> bool { self.event.shift_key() }
163 #[inline] pub fn alt_key(&self) -> bool { self.event.alt_key() }
164 #[inline] pub fn repeat(&self) -> bool { self.event.repeat() }
165 }
166 };
167}
168
169macro_rules! make_focus_event {
170 ($name:ident, $type:literal) => {
171 make_event!($name, $type => web_sys::FocusEvent);
172 };
173}
174
175macro_rules! make_drag_event {
176 ($name:ident, $type:literal) => {
177 make_mouse_event!($name, $type => web_sys::DragEvent);
178
179 impl $name {
180 #[inline] pub fn data_transfer(&self) -> Option<web_sys::DataTransfer> { self.event.data_transfer() }
181 }
182 };
183}
184
185macro_rules! make_input_event {
186 ($name:ident, $type:literal) => {
187 make_event!($name, $type => web_sys::InputEvent);
188
189 impl $name {
190 #[inline] pub fn data(&self) -> Option<String> { self.event.data() }
191 }
192 };
193}
194
195make_mouse_event!(Click, "click" => web_sys::MouseEvent);
196make_mouse_event!(MouseDown, "mousedown" => web_sys::MouseEvent);
197make_mouse_event!(MouseUp, "mouseup" => web_sys::MouseEvent);
198make_mouse_event!(MouseMove, "mousemove" => web_sys::MouseEvent);
199make_mouse_event!(MouseEnter, "mouseenter" => web_sys::MouseEvent);
200make_mouse_event!(MouseLeave, "mouseleave" => web_sys::MouseEvent);
201make_mouse_event!(DoubleClick, "dblclick" => web_sys::MouseEvent);
202make_mouse_event!(ContextMenu, "contextmenu" => web_sys::MouseEvent);
203
204make_keyboard_event!(KeyDown, "keydown");
205make_keyboard_event!(KeyUp, "keyup");
206
207make_focus_event!(Focus, "focus");
208make_focus_event!(Blur, "blur");
209
210make_drag_event!(DragStart, "dragstart");
211make_drag_event!(Drag, "drag");
212make_drag_event!(DragEnd, "dragend");
213make_drag_event!(DragOver, "dragover");
214make_drag_event!(DragEnter, "dragenter");
215make_drag_event!(DragLeave, "dragleave");
216make_drag_event!(Drop, "drop");
217
218make_input_event!(Input, "input");
219make_input_event!(BeforeInput, "beforeinput");
220
221make_event!(Load, "load" => web_sys::Event);
222make_event!(Scroll, "scroll" => web_sys::Event);
223make_event!(Resize, "resize" => web_sys::UiEvent);
224
225impl Input {
226 #[deprecated(since = "0.5.19", note = "Use with_node instead")]
228 pub fn value(&self) -> Option<String> {
229 let target = self.target()?;
230
231 if let Some(target) = target.dyn_ref::<HtmlInputElement>() {
232 Some(target.value())
234 } else if let Some(target) = target.dyn_ref::<HtmlTextAreaElement>() {
235 Some(target.value())
236 } else {
237 None
238 }
239 }
240}
241
242make_event!(Change, "change" => web_sys::Event);
243
244impl Change {
246 pub fn checked(&self) -> Option<bool> {
248 let target = self.dyn_target::<HtmlInputElement>()?;
249
250 match target.type_().as_str() {
251 "checkbox" | "radio" => Some(target.checked()),
252 _ => None,
253 }
254 }
255}