use crate::core::{ElementMaybeSignal, Position};
use crate::{
use_mouse_with_options, use_window, UseMouseCoordType, UseMouseEventExtractor, UseMouseOptions,
UseMouseReturn, UseMouseSourceType, UseWindow,
};
use cfg_if::cfg_if;
use default_struct_builder::DefaultBuilder;
use leptos::*;
use std::convert::Infallible;
use std::marker::PhantomData;
pub fn use_mouse_in_element<El, T>(target: El) -> UseMouseInElementReturn<impl Fn() + Clone>
where
El: Into<ElementMaybeSignal<T, web_sys::Element>> + Clone,
T: Into<web_sys::Element> + Clone + 'static,
{
use_mouse_in_element_with_options(target, Default::default())
}
pub fn use_mouse_in_element_with_options<El, T, OptEl, OptT, OptEx>(
target: El,
options: UseMouseInElementOptions<OptEl, OptT, OptEx>,
) -> UseMouseInElementReturn<impl Fn() + Clone>
where
El: Into<ElementMaybeSignal<T, web_sys::Element>> + Clone,
T: Into<web_sys::Element> + Clone + 'static,
OptEl: Into<ElementMaybeSignal<OptT, web_sys::EventTarget>> + Clone,
OptT: Into<web_sys::EventTarget> + Clone + 'static,
OptEx: UseMouseEventExtractor + Clone + 'static,
{
let UseMouseInElementOptions {
coord_type,
target: use_mouse_target,
touch,
reset_on_touch_ends,
initial_value,
handle_outside,
..
} = options;
let UseMouseReturn {
x, y, source_type, ..
} = use_mouse_with_options(
UseMouseOptions::default()
.coord_type(coord_type)
.target(use_mouse_target)
.touch(touch)
.reset_on_touch_ends(reset_on_touch_ends)
.initial_value(initial_value),
);
let (element_x, set_element_x) = create_signal(0.0);
let (element_y, set_element_y) = create_signal(0.0);
let (element_position_x, set_element_position_x) = create_signal(0.0);
let (element_position_y, set_element_position_y) = create_signal(0.0);
let (element_width, set_element_width) = create_signal(0.0);
let (element_height, set_element_height) = create_signal(0.0);
let (is_outside, set_outside) = create_signal(true);
cfg_if! { if #[cfg(feature = "ssr")] {
let stop = || ();
let _ = handle_outside;
let _ = set_element_x;
let _ = set_element_y;
let _ = set_element_position_x;
let _ = set_element_position_y;
let _ = set_element_width;
let _ = set_element_height;
let _ = set_outside;
let _ = target;
} else {
use crate::use_event_listener;
use leptos::ev::mouseleave;
let target = target.into();
let window = window();
let stop = watch(
move || (target.get(), x.get(), y.get()),
move |(el, x, y), _, _| {
if let Some(el) = el {
let el: web_sys::Element = el.clone().into();
let rect = el.get_bounding_client_rect();
let left = rect.left();
let top = rect.top();
let width = rect.width();
let height = rect.height();
set_element_position_x.set(left + window.page_x_offset().unwrap_or_default());
set_element_position_y.set(top + window.page_y_offset().unwrap_or_default());
set_element_height.set(height);
set_element_width.set(width);
let el_x = *x - element_position_x.get_untracked();
let el_y = *y - element_position_y.get_untracked();
set_outside.set(
width == 0.0
|| height == 0.0
|| el_x <= 0.0
|| el_y <= 0.0
|| el_x > width
|| el_y > height,
);
if handle_outside || !is_outside.get_untracked() {
set_element_x.set(el_x);
set_element_y.set(el_y);
}
}
},
false,
);
let _ = use_event_listener(document(), mouseleave, move |_| set_outside.set(true));
}}
UseMouseInElementReturn {
x,
y,
source_type,
element_x: element_x.into(),
element_y: element_y.into(),
element_position_x: element_position_x.into(),
element_position_y: element_position_y.into(),
element_width: element_width.into(),
element_height: element_height.into(),
is_outside: is_outside.into(),
stop,
}
}
#[derive(DefaultBuilder)]
pub struct UseMouseInElementOptions<El, T, Ex>
where
El: Clone + Into<ElementMaybeSignal<T, web_sys::EventTarget>>,
T: Into<web_sys::EventTarget> + Clone + 'static,
Ex: UseMouseEventExtractor + Clone,
{
coord_type: UseMouseCoordType<Ex>,
target: El,
touch: bool,
reset_on_touch_ends: bool,
initial_value: Position,
handle_outside: bool,
#[builder(skip)]
_marker: PhantomData<T>,
}
impl Default for UseMouseInElementOptions<UseWindow, web_sys::Window, Infallible> {
fn default() -> Self {
Self {
coord_type: UseMouseCoordType::default(),
target: use_window(),
touch: true,
reset_on_touch_ends: false,
initial_value: Position { x: 0.0, y: 0.0 },
handle_outside: true,
_marker: PhantomData,
}
}
}
pub struct UseMouseInElementReturn<F>
where
F: Fn() + Clone,
{
pub x: Signal<f64>,
pub y: Signal<f64>,
pub source_type: Signal<UseMouseSourceType>,
pub element_x: Signal<f64>,
pub element_y: Signal<f64>,
pub element_position_x: Signal<f64>,
pub element_position_y: Signal<f64>,
pub element_width: Signal<f64>,
pub element_height: Signal<f64>,
pub is_outside: Signal<bool>,
pub stop: F,
}