Skip to main content

freya_components/
cursor_area.rs

1use dioxus::prelude::*;
2use freya_core::platform::CursorIcon;
3use freya_elements as dioxus_elements;
4use freya_hooks::use_platform;
5
6/// Properties for the [`CursorArea`] component.
7#[derive(Props, Clone, PartialEq)]
8pub struct CursorAreaProps {
9    /// Cursor icon that will be used when hovering this area.
10    icon: CursorIcon,
11    /// Inner children for the CursorArea.
12    children: Element,
13}
14
15/// Change the cursor icon when it's hovering over this component.
16///
17/// # Example
18///
19/// ```no_run
20/// # use freya::prelude::*;
21/// # use freya_core::platform::CursorIcon;
22/// fn app() -> Element {
23///     rsx!(
24///         CursorArea {
25///             icon: CursorIcon::Progress,
26///             label {
27///                 height: "100%",
28///                 width: "100%",
29///                 "Loading"
30///             }
31///         }
32///     )
33/// }
34/// ```
35#[allow(non_snake_case)]
36pub fn CursorArea(CursorAreaProps { children, icon }: CursorAreaProps) -> Element {
37    let platform = use_platform();
38    let mut is_hovering = use_signal(|| false);
39
40    let onmousemove = move |_| {
41        *is_hovering.write() = true;
42        platform.set_cursor(icon);
43    };
44
45    let onmouseleave = move |_| {
46        *is_hovering.write() = false;
47        platform.set_cursor(CursorIcon::default());
48    };
49
50    use_drop(move || {
51        if *is_hovering.peek() {
52            platform.set_cursor(CursorIcon::default());
53        }
54    });
55
56    rsx!(
57        rect {
58            onmousemove,
59            onmouseleave,
60            {children}
61        }
62    )
63}
64
65#[cfg(test)]
66mod test {
67    use freya::prelude::*;
68    use freya_core::platform::CursorIcon;
69    use freya_testing::prelude::*;
70
71    #[tokio::test]
72    pub async fn cursor_area() {
73        fn cursor_area_app() -> Element {
74            rsx!(
75                CursorArea {
76                    icon: CursorIcon::Progress,
77                    rect {
78                        height: "50%",
79                        width: "100%",
80                    }
81                }
82                CursorArea {
83                    icon: CursorIcon::Pointer,
84                    rect {
85                        height: "50%",
86                        width: "100%",
87                    }
88                }
89            )
90        }
91
92        let mut utils = launch_test(cursor_area_app);
93
94        // Initial cursor
95        assert_eq!(utils.cursor_icon(), CursorIcon::default());
96
97        utils.move_cursor((100., 100.)).await;
98
99        // Cursor after hovering the first half
100        assert_eq!(utils.cursor_icon(), CursorIcon::Progress);
101
102        utils.move_cursor((100., 300.)).await;
103
104        // Cursor after hovering the second half
105        assert_eq!(utils.cursor_icon(), CursorIcon::Pointer);
106
107        utils.move_cursor((-1., -1.)).await;
108
109        // Cursor after leaving the window
110        assert_eq!(utils.cursor_icon(), CursorIcon::default());
111    }
112}