yew_hooks/hooks/
use_click_away.rs

1use std::rc::Rc;
2
3use web_sys::Node;
4use yew::{prelude::*, TargetCast};
5
6use super::{use_event_with_window, use_latest};
7
8/// A hook that triggers a callback when user clicks outside the target element.
9///
10/// # Example
11///
12/// ```rust
13/// # use yew::prelude::*;
14/// # use log::debug;
15/// #
16/// use yew_hooks::prelude::*;
17///
18/// #[function_component(UseClickAway)]
19/// fn click_away() -> Html {
20///     let node = use_node_ref();
21///
22///     use_click_away(node.clone(), move |_: Event| {
23///         debug!("Clicked outside!");
24///     });
25///     
26///     html! {
27///         <div ref={node}>
28///             { "Try to click outside of this area." }
29///         </div>
30///     }
31/// }
32/// ```
33#[hook]
34pub fn use_click_away<F>(node: NodeRef, callback: F)
35where
36    F: Fn(Event) + 'static,
37{
38    let callback_ref = use_latest(callback);
39
40    let handler = Rc::new(move |e: Event| {
41        if let Some(node) = &node.get() {
42            if let Some(target_node) = e.target_dyn_into::<Node>() {
43                if !node.contains(Some(&target_node)) {
44                    (*callback_ref.current())(e);
45                }
46            }
47        }
48    });
49
50    {
51        let handler = handler.clone();
52        use_event_with_window("mousedown", move |e: Event| {
53            handler(e);
54        });
55    }
56
57    use_event_with_window("touchstart", move |e: Event| {
58        handler(e);
59    });
60}