Skip to content

Commit 60be177

Browse files
committed
Implement focus events
1 parent 01a07fb commit 60be177

6 files changed

Lines changed: 129 additions & 8 deletions

File tree

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
use blitz_traits::events::{BlitzFocusEvent, DomEvent, DomEventData};
2+
3+
use crate::BaseDocument;
4+
5+
pub(crate) fn generate_focus_events(
6+
doc: &mut BaseDocument,
7+
update_focus: &mut dyn FnMut(&mut BaseDocument),
8+
dispatch_event: &mut dyn FnMut(DomEvent),
9+
) {
10+
// Update focus, tracking which node was focussed before and after
11+
let old_focus = doc.get_focussed_node_id();
12+
update_focus(doc);
13+
let new_focus = doc.get_focussed_node_id();
14+
15+
if old_focus == new_focus {
16+
return;
17+
}
18+
19+
if let Some(old_focus) = old_focus {
20+
dispatch_event(DomEvent::new(
21+
old_focus,
22+
DomEventData::Blur(BlitzFocusEvent),
23+
));
24+
dispatch_event(DomEvent::new(
25+
old_focus,
26+
DomEventData::FocusOut(BlitzFocusEvent),
27+
));
28+
}
29+
30+
if let Some(new_focus) = new_focus {
31+
dispatch_event(DomEvent::new(
32+
new_focus,
33+
DomEventData::Focus(BlitzFocusEvent),
34+
));
35+
dispatch_event(DomEvent::new(
36+
new_focus,
37+
DomEventData::FocusIn(BlitzFocusEvent),
38+
));
39+
}
40+
}

packages/blitz-dom/src/events/mod.rs

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
mod driver;
2+
mod focus;
23
mod ime;
34
mod keyboard;
45
mod mouse;
@@ -57,6 +58,10 @@ pub(crate) fn handle_dom_event<F: FnMut(DomEvent)>(
5758
DomEventData::Input(_) => None,
5859
DomEventData::Wheel(data) => Some(UiEvent::Wheel(data)),
5960
DomEventData::Scroll(_) => None,
61+
DomEventData::Focus(_) => None,
62+
DomEventData::Blur(_) => None,
63+
DomEventData::FocusIn(_) => None,
64+
DomEventData::FocusOut(_) => None,
6065
};
6166

6267
if let Some(ui_event) = ui_event {
@@ -87,7 +92,14 @@ pub(crate) fn handle_dom_event<F: FnMut(DomEvent)>(
8792
}
8893
}
8994
DomEventData::MouseDown(event) => {
90-
handle_mousedown(doc, target_node_id, event.x, event.y, event.mods);
95+
handle_mousedown(
96+
doc,
97+
target_node_id,
98+
event.x,
99+
event.y,
100+
event.mods,
101+
&mut dispatch_event,
102+
);
91103
}
92104
DomEventData::MouseUp(event) => {
93105
handle_mouseup(doc, target_node_id, event, dispatch_event);
@@ -134,5 +146,17 @@ pub(crate) fn handle_dom_event<F: FnMut(DomEvent)>(
134146
DomEventData::Wheel(event) => {
135147
handle_wheel(doc, target_node_id, event.clone(), dispatch_event);
136148
}
149+
DomEventData::Focus(_) => {
150+
// Do nothing (no default action)
151+
}
152+
DomEventData::Blur(_) => {
153+
// Do nothing (no default action)
154+
}
155+
DomEventData::FocusIn(_) => {
156+
// Do nothing (no default action)
157+
}
158+
DomEventData::FocusOut(_) => {
159+
// Do nothing (no default action)
160+
}
137161
}
138162
}

packages/blitz-dom/src/events/mouse.rs

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ use markup5ever::local_name;
1212

1313
use crate::{BaseDocument, node::SpecialElementData};
1414

15+
use super::focus::generate_focus_events;
16+
1517
pub(crate) fn handle_mousemove<F: FnMut(DomEvent)>(
1618
doc: &mut BaseDocument,
1719
target: usize,
@@ -86,6 +88,7 @@ pub(crate) fn handle_mousedown(
8688
x: f32,
8789
y: f32,
8890
mods: Modifiers,
91+
dispatch_event: &mut dyn FnMut(DomEvent),
8992
) {
9093
let Some(hit) = doc.hit(x, y) else {
9194
return;
@@ -152,7 +155,13 @@ pub(crate) fn handle_mousedown(
152155
}
153156

154157
drop(font_ctx);
155-
doc.set_focus_to(hit.node_id);
158+
generate_focus_events(
159+
doc,
160+
&mut |doc| {
161+
doc.set_focus_to(hit.node_id);
162+
},
163+
dispatch_event,
164+
);
156165
}
157166
}
158167

@@ -235,7 +244,13 @@ pub(crate) fn handle_click(
235244
node_id,
236245
DomEventData::Input(BlitzInputEvent { value }),
237246
));
238-
doc.set_focus_to(node_id);
247+
generate_focus_events(
248+
doc,
249+
&mut |doc| {
250+
doc.set_focus_to(node_id);
251+
},
252+
dispatch_event,
253+
);
239254
break 'matched true;
240255
}
241256
local_name!("input") if el.attr(local_name!("type")) == Some("radio") => {
@@ -249,7 +264,13 @@ pub(crate) fn handle_click(
249264
DomEventData::Input(BlitzInputEvent { value }),
250265
));
251266

252-
BaseDocument::set_focus_to(doc, node_id);
267+
generate_focus_events(
268+
doc,
269+
&mut |doc| {
270+
doc.set_focus_to(node_id);
271+
},
272+
dispatch_event,
273+
);
253274

254275
break 'matched true;
255276
}
@@ -336,7 +357,7 @@ pub(crate) fn handle_click(
336357

337358
// If nothing is matched then clear focus
338359
if !matched {
339-
doc.clear_focus();
360+
generate_focus_events(doc, &mut |doc| doc.clear_focus(), dispatch_event);
340361
}
341362

342363
// Assumed double click time to be less than 500ms, although may be system-dependant?

packages/blitz-traits/src/events.rs

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,10 @@ pub enum DomEventKind {
114114
KeyUp,
115115
Input,
116116
Ime,
117+
Focus,
118+
Blur,
119+
FocusIn,
120+
FocusOut,
117121
}
118122
impl DomEventKind {
119123
pub fn discriminant(self) -> u8 {
@@ -141,6 +145,10 @@ impl FromStr for DomEventKind {
141145
"keyup" => Ok(Self::KeyUp),
142146
"input" => Ok(Self::Input),
143147
"composition" => Ok(Self::Ime),
148+
"focus" => Ok(Self::Focus),
149+
"blur" => Ok(Self::Blur),
150+
"focusin" => Ok(Self::FocusIn),
151+
"focusout" => Ok(Self::FocusOut),
144152
_ => Err(()),
145153
}
146154
}
@@ -166,6 +174,10 @@ pub enum DomEventData {
166174
KeyUp(BlitzKeyEvent),
167175
Input(BlitzInputEvent),
168176
Ime(BlitzImeEvent),
177+
Focus(BlitzFocusEvent),
178+
Blur(BlitzFocusEvent),
179+
FocusIn(BlitzFocusEvent),
180+
FocusOut(BlitzFocusEvent),
169181
}
170182
impl DomEventData {
171183
pub fn discriminant(&self) -> u8 {
@@ -197,6 +209,10 @@ impl DomEventData {
197209
Self::KeyUp { .. } => "keyup",
198210
Self::Input { .. } => "input",
199211
Self::Ime { .. } => "composition",
212+
Self::Focus { .. } => "focus",
213+
Self::Blur { .. } => "blur",
214+
Self::FocusIn { .. } => "focusin",
215+
Self::FocusOut { .. } => "focusout",
200216
}
201217
}
202218

@@ -219,6 +235,10 @@ impl DomEventData {
219235
Self::KeyUp { .. } => DomEventKind::KeyUp,
220236
Self::Input { .. } => DomEventKind::Input,
221237
Self::Ime { .. } => DomEventKind::Ime,
238+
Self::Focus { .. } => DomEventKind::Focus,
239+
Self::Blur { .. } => DomEventKind::Blur,
240+
Self::FocusIn { .. } => DomEventKind::FocusIn,
241+
Self::FocusOut { .. } => DomEventKind::FocusOut,
222242
}
223243
}
224244

@@ -241,6 +261,10 @@ impl DomEventData {
241261
Self::KeyPress { .. } => true,
242262
Self::Ime { .. } => true,
243263
Self::Input { .. } => false,
264+
Self::Focus { .. } => false,
265+
Self::Blur { .. } => false,
266+
Self::FocusIn { .. } => false,
267+
Self::FocusOut { .. } => false,
244268
}
245269
}
246270

@@ -263,6 +287,10 @@ impl DomEventData {
263287
Self::KeyPress { .. } => true,
264288
Self::Ime { .. } => true,
265289
Self::Input { .. } => true,
290+
Self::Focus { .. } => false,
291+
Self::Blur { .. } => false,
292+
Self::FocusIn { .. } => true,
293+
Self::FocusOut { .. } => true,
266294
}
267295
}
268296
}
@@ -400,6 +428,9 @@ pub struct BlitzInputEvent {
400428
pub value: String,
401429
}
402430

431+
#[derive(Clone, Debug)]
432+
pub struct BlitzFocusEvent;
433+
403434
/// Copy of Winit IME event to avoid lower-level Blitz crates depending on winit
404435
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
405436
pub enum BlitzImeEvent {

packages/dioxus-native-dom/src/dioxus_document.rs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
//! Integration between Dioxus and Blitz
22
use crate::events::{
3-
BlitzKeyboardData, NativeClickData, NativeConverter, NativeFormData, NativeScrollData,
4-
NativeWheelData,
3+
BlitzKeyboardData, NativeClickData, NativeConverter, NativeFocusData, NativeFormData,
4+
NativeScrollData, NativeWheelData,
55
};
66
use crate::mutation_writer::{DioxusState, MutationWriter};
77
use crate::qual_name;
@@ -269,6 +269,11 @@ impl EventHandler for DioxusEventHandler<'_> {
269269
DomEventData::Scroll(sevent) => Some(wrap_event_data(NativeScrollData(sevent.clone()))),
270270
DomEventData::Wheel(wevent) => Some(wrap_event_data(NativeWheelData(wevent.clone()))),
271271

272+
DomEventData::Focus(_) => Some(wrap_event_data(NativeFocusData)),
273+
DomEventData::Blur(_) => Some(wrap_event_data(NativeFocusData)),
274+
DomEventData::FocusIn(_) => Some(wrap_event_data(NativeFocusData)),
275+
DomEventData::FocusOut(_) => Some(wrap_event_data(NativeFocusData)),
276+
272277
DomEventData::KeyDown(kevent)
273278
| DomEventData::KeyUp(kevent)
274279
| DomEventData::KeyPress(kevent) => {

packages/dioxus-native-dom/src/events.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -226,7 +226,7 @@ impl HasMouseData for NativeClickData {
226226
}
227227

228228
#[derive(Clone)]
229-
pub struct NativeFocusData {}
229+
pub struct NativeFocusData;
230230
impl HasFocusData for NativeFocusData {
231231
fn as_any(&self) -> &dyn Any {
232232
self as &dyn Any

0 commit comments

Comments
 (0)