by_components/effects/
mod.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
#![allow(non_snake_case)]
use dioxus::prelude::*;

/// A component that creates a shadow effect on hover.
///
/// # Example
///
/// ```rust
/// use dioxus::prelude::*;
/// use by_components::effects::HoverEffects;
///
/// #[component]
/// pub fn App() -> Element {
///     rsx! {
///         div {
///             HoverEffects {}
///             button { "Hover me" }
///             a { "Hover me" }
///             div { class: "hover-effect", "hover me" }
///             div { "Don't hover me" }
///         }
///     }
/// }
/// ```
///
/// # Output
///
/// It shows a shadow effect on all of <button/> and <a/> tags.
/// It also shows a shadow effect on the element starting with the class name "hover-effect".
#[component]
pub fn HoverEffects() -> Element {
    #[cfg(feature = "web")]
    use_effect(move || {
        tracing::debug!("shadow mounted");
        use wasm_bindgen::prelude::*;
        use web_sys::*;

        let document = web_sys::window().unwrap().document().unwrap();
        let shadow = document.get_element_by_id("shadow").unwrap();
        let closure = Closure::wrap(Box::new(move |event: web_sys::Event| {
            if let Ok(event) = event.dyn_into::<MouseEvent>() {
                if let Some(target) = event.target() {
                    if let Ok(el) = target.dyn_into::<HtmlElement>() {
                        if (el.tag_name().to_lowercase().as_str() == "button")
                            || (el.tag_name().to_lowercase().as_str() == "a")
                            || el
                                .class_name()
                                .split(" ")
                                .collect::<Vec<&str>>()
                                .contains(&"hover-effect")
                        {
                            let x = event.client_x();
                            let y = event.client_y();

                            shadow
                                .set_attribute("style", &format!("left: {}px; top: {}px; position: absolute; width: 50px; height: 50px; background: radial-gradient(circle, rgba(100, 100, 100, 0.5), rgba(0, 0, 0, 0)); border-radius: 50%; pointer-events: none; transform: translate(-50%, -50%); mix-blend-mode: screen; opacity: 0.7; filter: blur(15px); z-index: 9999; ", x, y))
                                .unwrap();
                        } else {
                            shadow.set_attribute("style", "display: none;").unwrap();
                        }
                    }
                }
            }
        }) as Box<dyn FnMut(web_sys::Event)>);

        document
            .add_event_listener_with_callback("mousemove", closure.as_ref().unchecked_ref())
            .unwrap();

        closure.forget();
    });

    rsx! {
        div { id: "shadow" }
    }
}