#![cfg_attr(feature = "ssr", allow(unused_variables, unused_imports))]
use crate::{
IntoElementMaybeSignal, UseEventListenerOptions, UseMouseCoordType, UseMouseOptions,
UseMouseReturn, UseMouseSourceType, use_event_listener_with_options,
};
use leptos::ev::{dragover, mousemove, touchend, touchmove, touchstart};
use leptos::prelude::*;
use std::convert::Infallible;
use wasm_bindgen::{JsCast, JsValue};
pub fn use_mouse() -> UseMouseReturn {
use_mouse_with_options(Default::default())
}
pub fn use_mouse_with_options<El, M, Ex>(options: UseMouseOptions<El, M, Ex>) -> UseMouseReturn
where
El: IntoElementMaybeSignal<web_sys::EventTarget, M>,
Ex: UseMouseEventExtractor + Clone + 'static,
{
let (x, set_x) = signal(options.initial_value.x);
let (y, set_y) = signal(options.initial_value.y);
let (source_type, set_source_type) = signal(UseMouseSourceType::Unset);
let mouse_handler = {
let coord_type = options.coord_type.clone();
move |event: web_sys::MouseEvent| {
let result = coord_type.extract_mouse_coords(&event);
if let Some((x, y)) = result {
set_x.set(x);
set_y.set(y);
set_source_type.set(UseMouseSourceType::Mouse);
}
}
};
let drag_handler = {
let mouse_handler = mouse_handler.clone();
move |event: web_sys::DragEvent| {
let js_value: &JsValue = event.as_ref();
mouse_handler(js_value.clone().unchecked_into::<web_sys::MouseEvent>());
}
};
let touch_handler = {
let coord_type = options.coord_type.clone();
move |event: web_sys::TouchEvent| {
let touches = event.touches();
if touches.length() > 0 {
let result = coord_type.extract_touch_coords(
&touches
.get(0)
.expect("Just checked that there's at least on touch"),
);
if let Some((x, y)) = result {
set_x.set(x);
set_y.set(y);
set_source_type.set(UseMouseSourceType::Touch);
}
}
}
};
let initial_value = options.initial_value;
let reset = move || {
set_x.set(initial_value.x);
set_y.set(initial_value.y);
};
#[cfg(not(feature = "ssr"))]
{
let target = options.target.into_element_maybe_signal();
let event_listener_options = UseEventListenerOptions::default().passive(true);
let _ = use_event_listener_with_options(
target,
mousemove,
mouse_handler,
event_listener_options,
);
let _ =
use_event_listener_with_options(target, dragover, drag_handler, event_listener_options);
if options.touch && !matches!(options.coord_type, UseMouseCoordType::Movement) {
let _ = use_event_listener_with_options(
target,
touchstart,
touch_handler.clone(),
event_listener_options,
);
let _ = use_event_listener_with_options(
target,
touchmove,
touch_handler,
event_listener_options,
);
if options.reset_on_touch_ends {
let _ = use_event_listener_with_options(
target,
touchend,
move |_| reset(),
event_listener_options,
);
}
}
}
UseMouseReturn {
x: x.into(),
y: y.into(),
set_x,
set_y,
source_type: source_type.into(),
}
}
#[allow(unused_variables)]
pub trait UseMouseEventExtractor {
fn extract_mouse_coords(&self, event: &web_sys::MouseEvent) -> Option<(f64, f64)> {
None
}
fn extract_touch_coords(&self, touch: &web_sys::Touch) -> Option<(f64, f64)> {
None
}
}
impl UseMouseEventExtractor for Infallible {
fn extract_mouse_coords(&self, _: &web_sys::MouseEvent) -> Option<(f64, f64)> {
unreachable!()
}
fn extract_touch_coords(&self, _: &web_sys::Touch) -> Option<(f64, f64)> {
unreachable!()
}
}