Skip to main content

euv_ui/hook/use_hover/
fn.rs

1use super::*;
2
3/// Obtains the [`UseHover`] registered against the current hook context
4/// slot.
5///
6/// Behaves like `HookContext::use_hook` - the same handle is returned on
7/// every render at the same hook index, so the document listeners are
8/// attached once and the hover state survives re-renders.
9///
10/// Attach `get_target()` to the caller's markup with the `ref:`
11/// attribute, then read `get_hovered()` inside a render closure to
12/// react to the pointer entering or leaving.
13///
14/// # Returns
15///
16/// - `UseHover` - The handle, with `get_target()` returning the
17///   [`NodeRef`] and `get_hovered()` the reactive `Signal<bool>`.
18pub fn use_hover() -> UseHover {
19    let handle: UseHover = HookContext::use_hook(|| {
20        let handle: UseHover = UseHover::new();
21        handle.attach();
22        handle
23    });
24    App::use_cleanup({
25        let handle: UseHover = handle.clone();
26        move || handle.detach()
27    });
28    handle
29}
30
31/// Reports whether a pointer event landed inside the watched element.
32///
33/// # Arguments
34///
35/// - `&NodeRef<Element>` - The element being watched.
36/// - `&Event` - The pointer event.
37///
38/// # Returns
39///
40/// - `bool` - `true` when the event's node is inside the element.
41#[cfg(target_arch = "wasm32")]
42pub(crate) fn pointer_is_inside(target: &NodeRef<Element>, event: &Event) -> bool {
43    let Some(node) = event
44        .target()
45        .and_then(|target: EventTarget| target.dyn_into::<Node>().ok())
46    else {
47        return false;
48    };
49    let Some(element) = target.get_cloned() else {
50        return false;
51    };
52    node_contains(&element, &node)
53}