adui_dioxus/components/
interaction.rs1use dioxus::events::PointerData;
7use dioxus::prelude::*;
8use wasm_bindgen::JsCast;
9
10#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
12pub struct PointerState {
13 pub active_id: Option<i32>,
14 pub dragging: bool,
15}
16
17pub fn as_pointer_event(evt: &Event<PointerData>) -> Option<web_sys::PointerEvent> {
19 evt.data().downcast::<web_sys::PointerEvent>().cloned()
20}
21
22pub fn start_pointer(state: &mut Signal<PointerState>, evt: &web_sys::PointerEvent) {
24 state.set(PointerState {
25 active_id: Some(evt.pointer_id()),
26 dragging: true,
27 });
28
29 if let Some(target) = evt
30 .target()
31 .and_then(|t| t.dyn_into::<web_sys::Element>().ok())
32 {
33 let _ = target.set_pointer_capture(evt.pointer_id());
34 }
35}
36
37pub fn end_pointer(state: &mut Signal<PointerState>, evt: &web_sys::PointerEvent) {
39 let should_end = {
40 let reader = state.read();
41 reader.active_id == Some(evt.pointer_id())
42 };
43 if !should_end {
44 return;
45 }
46
47 if let Some(target) = evt
48 .target()
49 .and_then(|t| t.dyn_into::<web_sys::Element>().ok())
50 {
51 let _ = target.release_pointer_capture(evt.pointer_id());
52 }
53
54 state.set(PointerState {
55 active_id: None,
56 dragging: false,
57 });
58}
59
60pub fn is_active_pointer(state: &Signal<PointerState>, evt: &web_sys::PointerEvent) -> bool {
62 state.read().active_id == Some(evt.pointer_id())
63}
64
65pub fn reset_pointer(state: &mut Signal<PointerState>) {
67 state.set(PointerState {
68 active_id: None,
69 dragging: false,
70 });
71}
72
73#[cfg(test)]
74mod interaction_tests {
75 use super::*;
76
77 #[test]
78 fn pointer_state_default() {
79 let state = PointerState::default();
80 assert_eq!(state.active_id, None);
81 assert_eq!(state.dragging, false);
82 }
83
84 #[test]
85 fn pointer_state_partial_eq() {
86 let state1 = PointerState {
87 active_id: Some(1),
88 dragging: true,
89 };
90 let state2 = PointerState {
91 active_id: Some(1),
92 dragging: true,
93 };
94 let state3 = PointerState {
95 active_id: Some(2),
96 dragging: true,
97 };
98 let state4 = PointerState {
99 active_id: Some(1),
100 dragging: false,
101 };
102
103 assert_eq!(state1, state2);
104 assert_ne!(state1, state3);
105 assert_ne!(state1, state4);
106 }
107
108 #[test]
109 fn pointer_state_debug() {
110 let state = PointerState {
111 active_id: Some(42),
112 dragging: true,
113 };
114 let debug_str = format!("{:?}", state);
115 assert!(debug_str.contains("PointerState"));
116 assert!(debug_str.contains("42") || debug_str.contains("Some"));
117 }
118
119 #[test]
120 fn pointer_state_clone() {
121 let state1 = PointerState {
122 active_id: Some(10),
123 dragging: true,
124 };
125 let state2 = state1;
126 assert_eq!(state1, state2);
127 }
128
129 #[test]
130 fn pointer_state_copy() {
131 let state1 = PointerState {
132 active_id: Some(5),
133 dragging: false,
134 };
135 let state2 = state1;
136 assert_eq!(state1.active_id, Some(5));
138 assert_eq!(state2.active_id, Some(5));
139 }
140
141 #[test]
142 fn reset_pointer_logic() {
143 let reset_state = PointerState {
145 active_id: None,
146 dragging: false,
147 };
148 assert_eq!(reset_state.active_id, None);
149 assert_eq!(reset_state.dragging, false);
150 }
151
152 #[test]
153 fn is_active_pointer_logic() {
154 let state_with_id = PointerState {
156 active_id: Some(42),
157 dragging: true,
158 };
159 assert_eq!(state_with_id.active_id, Some(42));
161
162 let state_without_id = PointerState {
163 active_id: None,
164 dragging: false,
165 };
166 assert_eq!(state_without_id.active_id, None);
167 }
168}