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}