radix_leptos_core/utils/
events.rs

1use web_sys::{Event, EventTarget, MouseEvent, KeyboardEvent, FocusEvent};
2use wasm_bindgen::{JsCast, JsValue};
3
4/// Utility functions for event handling and composition
5
6/// Compose multiple event handlers into a single handler
7pub fn compose_event_handlers<E, F1, F2>(
8    handler1: Option<F1>, 
9    handler2: Option<F2>,
10) -> impl Fn(E)
11where
12    E: Clone,
13    F1: Fn(E),
14    F2: Fn(E),
15{
16    move |event: E| {
17        if let Some(ref h1) = handler1 {
18            h1(event.clone());
19        }
20        if let Some(ref h2) = handler2 {
21            h2(event);
22        }
23    }
24}
25
26/// Check if an event should be handled based on keyboard modifiers
27pub fn should_handle_key_event(event: &KeyboardEvent, key: &str, modifiers: Option<KeyModifiers>) -> bool {
28    if event.key() != key {
29        return false;
30    }
31    
32    if let Some(mods) = modifiers {
33        return event.ctrl_key() == mods.ctrl &&
34               event.shift_key() == mods.shift &&
35               event.alt_key() == mods.alt &&
36               event.meta_key() == mods.meta;
37    }
38    
39    true
40}
41
42/// Keyboard modifier state
43#[derive(Debug, Clone, PartialEq)]
44pub struct KeyModifiers {
45    pub ctrl: bool,
46    pub shift: bool,
47    pub alt: bool,
48    pub meta: bool,
49}
50
51impl KeyModifiers {
52    pub fn none() -> Self {
53        Self {
54            ctrl: false,
55            shift: false,
56            alt: false,
57            meta: false,
58        }
59    }
60    
61    pub fn ctrl() -> Self {
62        Self {
63            ctrl: true,
64            shift: false,
65            alt: false,
66            meta: false,
67        }
68    }
69    
70    pub fn shift() -> Self {
71        Self {
72            ctrl: false,
73            shift: true,
74            alt: false,
75            meta: false,
76        }
77    }
78}
79
80/// Prevent default and stop propagation on an event
81pub fn prevent_default_and_stop_propagation(event: &Event) {
82    event.prevent_default();
83    event.stop_propagation();
84}
85
86/// Get the target element of an event, safely cast to Element
87pub fn get_event_target_element(event: &Event) -> Option<web_sys::Element> {
88    event
89        .target()?
90        .dyn_into()
91        .ok()
92}
93
94/// Create a synthetic keyboard event for testing
95#[cfg(test)]
96pub fn create_keyboard_event(event_type: &str, key: &str, modifiers: Option<KeyModifiers>) -> KeyboardEvent {
97    use web_sys::KeyboardEventInit;
98    
99    let mut init = KeyboardEventInit::new();
100    init.key(key);
101    
102    if let Some(mods) = modifiers {
103        init.ctrl_key(mods.ctrl);
104        init.shift_key(mods.shift);
105        init.alt_key(mods.alt);
106        init.meta_key(mods.meta);
107    }
108    
109    KeyboardEvent::new_with_keyboard_event_init_dict(event_type, &init)
110        .expect("Failed to create keyboard event")
111}
112
113/// Create a synthetic mouse event for testing  
114#[cfg(test)]
115pub fn create_mouse_event(event_type: &str) -> MouseEvent {
116    MouseEvent::new(event_type).expect("Failed to create mouse event")
117}
118
119#[cfg(test)]
120mod tests {
121    use super::*;
122    use wasm_bindgen_test::*;
123    
124    wasm_bindgen_test_configure!(run_in_browser);
125    
126    #[test]
127    fn test_key_modifiers() {
128        let none = KeyModifiers::none();
129        assert!(!none.ctrl && !none.shift && !none.alt && !none.meta);
130        
131        let ctrl = KeyModifiers::ctrl();
132        assert!(ctrl.ctrl && !ctrl.shift && !ctrl.alt && !ctrl.meta);
133        
134        let shift = KeyModifiers::shift();
135        assert!(!shift.ctrl && shift.shift && !shift.alt && !shift.meta);
136    }
137    
138    #[wasm_bindgen_test]
139    fn test_keyboard_event_creation() {
140        let event = create_keyboard_event("keydown", "Enter", Some(KeyModifiers::ctrl()));
141        
142        assert_eq!(event.key(), "Enter");
143        assert!(event.ctrl_key());
144        assert!(!event.shift_key());
145    }
146    
147    #[wasm_bindgen_test]
148    fn test_should_handle_key_event() {
149        let event = create_keyboard_event("keydown", "Escape", None);
150        
151        assert!(should_handle_key_event(&event, "Escape", None));
152        assert!(!should_handle_key_event(&event, "Enter", None));
153        
154        let event_with_ctrl = create_keyboard_event("keydown", "s", Some(KeyModifiers::ctrl()));
155        assert!(should_handle_key_event(&event_with_ctrl, "s", Some(KeyModifiers::ctrl())));
156        assert!(!should_handle_key_event(&event_with_ctrl, "s", None));
157    }
158}