2023-09-13 01:32:07 +01:00
|
|
|
use crate::{UseDocument, UseWindow};
|
2023-10-28 16:18:29 -05:00
|
|
|
use cfg_if::cfg_if;
|
2024-07-23 10:50:20 -06:00
|
|
|
use leptos::html::{CreateElement, ElementType};
|
2024-05-07 12:41:44 +01:00
|
|
|
use leptos::prelude::wrappers::read::Signal;
|
|
|
|
use leptos::prelude::*;
|
2024-07-23 10:50:20 -06:00
|
|
|
use send_wrapper::SendWrapper;
|
2023-05-26 18:09:01 +01:00
|
|
|
use std::marker::PhantomData;
|
2024-07-23 10:50:20 -06:00
|
|
|
use wasm_bindgen::JsCast;
|
2023-05-14 22:45:38 +01:00
|
|
|
|
2023-05-14 23:50:11 +01:00
|
|
|
/// Used as an argument type to make it easily possible to pass either
|
2024-07-27 18:35:59 +02:00
|
|
|
///
|
2024-05-28 11:47:10 +10:00
|
|
|
/// * a `web_sys` element that implements `E` (for example `EventTarget`, `Element` or `HtmlElement`),
|
2023-05-14 23:50:11 +01:00
|
|
|
/// * an `Option<T>` where `T` is the web_sys element,
|
|
|
|
/// * a `Signal<T>` where `T` is the web_sys element,
|
|
|
|
/// * a `Signal<Option<T>>` where `T` is the web_sys element,
|
|
|
|
/// * a `NodeRef`
|
2024-07-27 18:35:59 +02:00
|
|
|
///
|
2024-07-27 18:10:38 +02:00
|
|
|
/// into a function. Used for example in [`fn@crate::use_event_listener`].
|
2023-05-26 18:09:01 +01:00
|
|
|
pub enum ElementMaybeSignal<T, E>
|
2024-02-23 02:40:54 +00:00
|
|
|
where
|
|
|
|
T: Into<E> + Clone + 'static,
|
2023-05-14 22:45:38 +01:00
|
|
|
{
|
2024-08-03 23:28:09 -06:00
|
|
|
Static(SendWrapper<Option<T>>),
|
|
|
|
Dynamic(Signal<Option<T>, LocalStorage>),
|
2024-07-23 10:50:20 -06:00
|
|
|
_Phantom(PhantomData<fn() -> E>),
|
2023-05-14 22:45:38 +01:00
|
|
|
}
|
|
|
|
|
2023-05-26 18:09:01 +01:00
|
|
|
impl<T, E> Default for ElementMaybeSignal<T, E>
|
2024-02-23 02:40:54 +00:00
|
|
|
where
|
|
|
|
T: Into<E> + Clone + 'static,
|
2023-05-14 23:50:11 +01:00
|
|
|
{
|
|
|
|
fn default() -> Self {
|
2024-08-03 23:28:09 -06:00
|
|
|
Self::Static(SendWrapper::new(None))
|
2023-05-14 23:50:11 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-05-26 18:09:01 +01:00
|
|
|
impl<T, E> Clone for ElementMaybeSignal<T, E>
|
2024-02-23 02:40:54 +00:00
|
|
|
where
|
|
|
|
T: Into<E> + Clone + 'static,
|
2023-05-14 23:50:11 +01:00
|
|
|
{
|
|
|
|
fn clone(&self) -> Self {
|
|
|
|
match self {
|
|
|
|
Self::Static(t) => Self::Static(t.clone()),
|
|
|
|
Self::Dynamic(s) => Self::Dynamic(*s),
|
2023-05-26 18:09:01 +01:00
|
|
|
_ => unreachable!(),
|
2023-05-14 23:50:11 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-07-19 20:22:27 -06:00
|
|
|
impl<T, E> DefinedAt for ElementMaybeSignal<T, E>
|
2024-02-23 02:40:54 +00:00
|
|
|
where
|
|
|
|
T: Into<E> + Clone + 'static,
|
2023-05-14 23:50:11 +01:00
|
|
|
{
|
2024-07-19 20:22:27 -06:00
|
|
|
fn defined_at(&self) -> Option<&'static std::panic::Location<'static>> {
|
|
|
|
None
|
2023-05-14 23:50:11 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-07-19 20:22:27 -06:00
|
|
|
impl<T, E> With for ElementMaybeSignal<T, E>
|
2024-02-23 02:40:54 +00:00
|
|
|
where
|
|
|
|
T: Into<E> + Clone + 'static,
|
2023-05-14 23:50:11 +01:00
|
|
|
{
|
2023-08-31 04:41:42 +01:00
|
|
|
type Value = Option<T>;
|
|
|
|
|
2023-05-14 23:50:11 +01:00
|
|
|
fn with<O>(&self, f: impl FnOnce(&Option<T>) -> O) -> O {
|
|
|
|
match self {
|
2024-08-03 23:28:09 -06:00
|
|
|
Self::Static(t) => f(&t),
|
|
|
|
Self::Dynamic(s) => {
|
|
|
|
let value = s.get();
|
2024-07-23 10:50:20 -06:00
|
|
|
f(&value)
|
|
|
|
}
|
2023-05-26 18:09:01 +01:00
|
|
|
_ => unreachable!(),
|
2023-05-14 23:50:11 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn try_with<O>(&self, f: impl FnOnce(&Option<T>) -> O) -> Option<O> {
|
|
|
|
match self {
|
2024-08-03 23:28:09 -06:00
|
|
|
Self::Static(t) => Some(f(&t)),
|
|
|
|
Self::Dynamic(s) => s.try_with(f),
|
2023-05-26 18:09:01 +01:00
|
|
|
_ => unreachable!(),
|
2023-05-14 23:50:11 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-07-19 20:22:27 -06:00
|
|
|
impl<T, E> WithUntracked for ElementMaybeSignal<T, E>
|
2024-02-23 02:40:54 +00:00
|
|
|
where
|
|
|
|
T: Into<E> + Clone + 'static,
|
2023-05-14 23:50:11 +01:00
|
|
|
{
|
2023-08-31 04:41:42 +01:00
|
|
|
type Value = Option<T>;
|
|
|
|
|
2023-05-14 23:50:11 +01:00
|
|
|
fn with_untracked<O>(&self, f: impl FnOnce(&Option<T>) -> O) -> O {
|
|
|
|
match self {
|
2024-08-03 23:28:09 -06:00
|
|
|
Self::Static(t) => f(&t),
|
|
|
|
Self::Dynamic(s) => s.with_untracked(f),
|
2023-05-26 18:09:01 +01:00
|
|
|
_ => unreachable!(),
|
2023-05-14 23:50:11 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn try_with_untracked<O>(&self, f: impl FnOnce(&Option<T>) -> O) -> Option<O> {
|
|
|
|
match self {
|
2024-08-03 23:28:09 -06:00
|
|
|
Self::Static(t) => Some(f(&t)),
|
|
|
|
Self::Dynamic(s) => s.try_with_untracked(f),
|
2023-05-26 18:09:01 +01:00
|
|
|
_ => unreachable!(),
|
2023-05-14 23:50:11 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-06-13 00:31:38 +01:00
|
|
|
// From static element //////////////////////////////////////////////////////////////
|
|
|
|
|
2023-07-27 18:06:36 +01:00
|
|
|
impl<T, E> From<T> for ElementMaybeSignal<T, E>
|
2024-02-23 02:40:54 +00:00
|
|
|
where
|
|
|
|
T: Into<E> + Clone + 'static,
|
2023-05-14 22:45:38 +01:00
|
|
|
{
|
2023-07-27 18:06:36 +01:00
|
|
|
fn from(value: T) -> Self {
|
2024-08-03 23:28:09 -06:00
|
|
|
ElementMaybeSignal::Static(SendWrapper::new(Some(value)))
|
2023-05-14 22:45:38 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-07-27 18:06:36 +01:00
|
|
|
impl<T, E> From<Option<T>> for ElementMaybeSignal<T, E>
|
2024-02-23 02:40:54 +00:00
|
|
|
where
|
|
|
|
T: Into<E> + Clone + 'static,
|
2023-05-14 22:45:38 +01:00
|
|
|
{
|
2023-07-27 18:06:36 +01:00
|
|
|
fn from(target: Option<T>) -> Self {
|
2024-08-03 23:28:09 -06:00
|
|
|
ElementMaybeSignal::Static(SendWrapper::new(target))
|
2023-05-14 22:45:38 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-09-13 01:32:07 +01:00
|
|
|
macro_rules! impl_from_deref_option {
|
|
|
|
($ty:ty, $ty2:ty) => {
|
|
|
|
impl<E> From<$ty> for ElementMaybeSignal<$ty2, E>
|
|
|
|
where
|
|
|
|
E: From<$ty2> + 'static,
|
|
|
|
{
|
|
|
|
fn from(value: $ty) -> Self {
|
2024-08-03 23:28:09 -06:00
|
|
|
Self::Static(SendWrapper::new((*value).clone()))
|
2023-09-13 01:32:07 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
impl_from_deref_option!(UseWindow, web_sys::Window);
|
|
|
|
impl_from_deref_option!(UseDocument, web_sys::Document);
|
|
|
|
|
2023-06-13 00:31:38 +01:00
|
|
|
// From string (selector) ///////////////////////////////////////////////////////////////
|
|
|
|
|
2023-06-23 22:04:16 +01:00
|
|
|
impl<'a, E> From<&'a str> for ElementMaybeSignal<web_sys::Element, E>
|
2024-02-23 02:40:54 +00:00
|
|
|
where
|
|
|
|
E: From<web_sys::Element> + 'static,
|
2023-06-23 22:04:16 +01:00
|
|
|
{
|
|
|
|
fn from(target: &'a str) -> Self {
|
2023-10-28 16:18:29 -05:00
|
|
|
cfg_if! { if #[cfg(feature = "ssr")] {
|
2023-11-09 23:26:47 +00:00
|
|
|
let _ = target;
|
2024-08-03 23:28:09 -06:00
|
|
|
Self::Static(SendWrapper::new(None))
|
2023-10-28 16:18:29 -05:00
|
|
|
} else {
|
2024-08-03 23:28:09 -06:00
|
|
|
Self::Static(SendWrapper::new(document().query_selector(target).unwrap_or_default()))
|
2023-10-28 16:18:29 -05:00
|
|
|
}}
|
2023-06-23 22:04:16 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<E> From<String> for ElementMaybeSignal<web_sys::Element, E>
|
2024-02-23 02:40:54 +00:00
|
|
|
where
|
|
|
|
E: From<web_sys::Element> + 'static,
|
2023-06-23 22:04:16 +01:00
|
|
|
{
|
|
|
|
fn from(target: String) -> Self {
|
2023-10-28 16:18:29 -05:00
|
|
|
Self::from(target.as_str())
|
2023-06-23 22:04:16 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-01-10 23:37:32 +00:00
|
|
|
macro_rules! impl_from_signal_string {
|
|
|
|
($ty:ty) => {
|
|
|
|
impl<E> From<$ty> for ElementMaybeSignal<web_sys::Element, E>
|
|
|
|
where
|
|
|
|
E: From<web_sys::Element> + 'static,
|
|
|
|
{
|
|
|
|
fn from(signal: $ty) -> Self {
|
|
|
|
cfg_if! { if #[cfg(feature = "ssr")] {
|
|
|
|
let _ = signal;
|
2024-08-03 23:28:09 -06:00
|
|
|
Self::Dynamic(Signal::derive_local(|| None))
|
2024-01-10 23:37:32 +00:00
|
|
|
} else {
|
|
|
|
Self::Dynamic(
|
2024-08-03 23:28:09 -06:00
|
|
|
Signal::derive_local(move || document().query_selector(&signal.get()).unwrap_or_default()),
|
2024-01-10 23:37:32 +00:00
|
|
|
)
|
|
|
|
}}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
2023-06-13 00:31:38 +01:00
|
|
|
}
|
|
|
|
|
2024-01-10 23:37:32 +00:00
|
|
|
impl_from_signal_string!(Signal<String>);
|
|
|
|
impl_from_signal_string!(ReadSignal<String>);
|
|
|
|
impl_from_signal_string!(RwSignal<String>);
|
|
|
|
impl_from_signal_string!(Memo<String>);
|
|
|
|
|
2024-08-03 23:28:09 -06:00
|
|
|
impl_from_signal_string!(Signal<&'static str>);
|
|
|
|
impl_from_signal_string!(ReadSignal<&'static str>);
|
2024-07-23 21:33:14 -06:00
|
|
|
impl_from_signal_string!(RwSignal<&'static str>);
|
|
|
|
impl_from_signal_string!(Memo<&'static str>);
|
2024-01-10 23:37:32 +00:00
|
|
|
|
2023-06-13 00:31:38 +01:00
|
|
|
// From signal ///////////////////////////////////////////////////////////////
|
|
|
|
|
2023-05-14 22:45:38 +01:00
|
|
|
macro_rules! impl_from_signal_option {
|
|
|
|
($ty:ty) => {
|
2023-07-27 18:06:36 +01:00
|
|
|
impl<T, E> From<$ty> for ElementMaybeSignal<T, E>
|
2023-05-14 22:45:38 +01:00
|
|
|
where
|
2023-05-26 18:09:01 +01:00
|
|
|
T: Into<E> + Clone + 'static,
|
2023-05-14 22:45:38 +01:00
|
|
|
{
|
2023-07-27 18:06:36 +01:00
|
|
|
fn from(target: $ty) -> Self {
|
|
|
|
Self::Dynamic(target.into())
|
2023-05-14 22:45:38 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2024-08-03 23:28:09 -06:00
|
|
|
impl_from_signal_option!(Signal<Option<T>, LocalStorage>);
|
|
|
|
impl_from_signal_option!(ReadSignal<Option<T>, LocalStorage>);
|
|
|
|
impl_from_signal_option!(RwSignal<Option<T>, LocalStorage>);
|
|
|
|
impl_from_signal_option!(Memo<Option<T>, LocalStorage>);
|
2023-05-14 22:45:38 +01:00
|
|
|
|
|
|
|
macro_rules! impl_from_signal {
|
|
|
|
($ty:ty) => {
|
2023-07-27 18:06:36 +01:00
|
|
|
impl<T, E> From<$ty> for ElementMaybeSignal<T, E>
|
2023-05-14 22:45:38 +01:00
|
|
|
where
|
2023-05-26 18:09:01 +01:00
|
|
|
T: Into<E> + Clone + 'static,
|
2023-05-14 22:45:38 +01:00
|
|
|
{
|
2023-07-27 18:06:36 +01:00
|
|
|
fn from(signal: $ty) -> Self {
|
2024-08-03 23:28:09 -06:00
|
|
|
Self::Dynamic(Signal::derive_local(move || Some(signal.get())))
|
2023-05-14 22:45:38 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2024-08-03 23:28:09 -06:00
|
|
|
impl_from_signal!(Signal<T, LocalStorage>);
|
|
|
|
impl_from_signal!(ReadSignal<T, LocalStorage>);
|
|
|
|
impl_from_signal!(RwSignal<T, LocalStorage>);
|
|
|
|
impl_from_signal!(Memo<T, LocalStorage>);
|
2023-05-14 22:45:38 +01:00
|
|
|
|
2023-06-13 00:31:38 +01:00
|
|
|
// From NodeRef //////////////////////////////////////////////////////////////
|
|
|
|
|
2023-05-26 18:09:01 +01:00
|
|
|
macro_rules! impl_from_node_ref {
|
|
|
|
($ty:ty) => {
|
2023-07-27 18:06:36 +01:00
|
|
|
impl<R> From<NodeRef<R>> for ElementMaybeSignal<$ty, $ty>
|
2023-05-26 18:09:01 +01:00
|
|
|
where
|
2024-07-23 10:50:20 -06:00
|
|
|
R: ElementType + CreateElement<Dom> + Clone + Send + Sync + 'static,
|
|
|
|
R::Output: JsCast + Into<$ty> + Clone + 'static,
|
2023-05-26 18:09:01 +01:00
|
|
|
{
|
2023-07-27 18:06:36 +01:00
|
|
|
fn from(node_ref: NodeRef<R>) -> Self {
|
2024-08-03 23:28:09 -06:00
|
|
|
Self::Dynamic(Signal::derive_local(move || {
|
2023-05-26 18:09:01 +01:00
|
|
|
node_ref.get().map(move |el| {
|
2024-07-23 10:50:20 -06:00
|
|
|
let el: $ty = el.clone().into();
|
2024-08-03 23:28:09 -06:00
|
|
|
el
|
2023-05-26 18:09:01 +01:00
|
|
|
})
|
|
|
|
}))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
2023-05-14 22:45:38 +01:00
|
|
|
}
|
2023-05-26 18:09:01 +01:00
|
|
|
|
|
|
|
impl_from_node_ref!(web_sys::EventTarget);
|
|
|
|
impl_from_node_ref!(web_sys::Element);
|
2024-05-28 11:47:10 +10:00
|
|
|
impl_from_node_ref!(web_sys::HtmlElement);
|
2024-01-10 23:37:32 +00:00
|
|
|
|
2024-07-23 10:50:20 -06:00
|
|
|
// // From leptos::html::HTMLElement ///////////////////////////////////////////////
|
|
|
|
//
|
|
|
|
// macro_rules! impl_from_html_element {
|
|
|
|
// ($ty:ty) => {
|
|
|
|
// impl<HtmlEl> From<HtmlElement<HtmlEl>> for ElementMaybeSignal<$ty, $ty>
|
|
|
|
// where
|
|
|
|
// HtmlEl: ElementDescriptor + std::ops::Deref<Target = $ty>,
|
|
|
|
// {
|
|
|
|
// fn from(value: HtmlElement<HtmlEl>) -> Self {
|
|
|
|
// let el: &$ty = value.deref();
|
|
|
|
// Self::Static(Some(el.clone()))
|
|
|
|
// }
|
|
|
|
// }
|
|
|
|
// };
|
|
|
|
// }
|
|
|
|
//
|
|
|
|
// impl_from_html_element!(web_sys::EventTarget);
|
|
|
|
// impl_from_html_element!(web_sys::Element);
|
|
|
|
// impl_from_html_element!(web_sys::HtmlElement);
|
|
|
|
//
|
|
|
|
// // From Signal<leptos::html::HTMLElement> /////////////////////////////////////////
|
|
|
|
//
|
|
|
|
// macro_rules! impl_from_signal_html_element {
|
|
|
|
// ($signal:ty, $ty:ty) => {
|
|
|
|
// impl<HtmlEl> From<$signal> for ElementMaybeSignal<$ty, $ty>
|
|
|
|
// where
|
|
|
|
// HtmlEl: ElementDescriptor + std::ops::Deref<Target = $ty> + Clone,
|
|
|
|
// {
|
|
|
|
// fn from(value: $signal) -> Self {
|
|
|
|
// Self::Dynamic(Signal::derive(move || {
|
|
|
|
// let value = value.get();
|
|
|
|
// let el: &$ty = value.deref();
|
|
|
|
// Some(el.clone())
|
|
|
|
// }))
|
|
|
|
// }
|
|
|
|
// }
|
|
|
|
// };
|
|
|
|
// }
|
|
|
|
//
|
|
|
|
// impl_from_signal_html_element!(Signal<HtmlElement<HtmlEl>>, web_sys::EventTarget);
|
|
|
|
// impl_from_signal_html_element!(ReadSignal<HtmlElement<HtmlEl>>, web_sys::EventTarget);
|
|
|
|
// impl_from_signal_html_element!(RwSignal<HtmlElement<HtmlEl>>, web_sys::EventTarget);
|
|
|
|
// impl_from_signal_html_element!(Memo<HtmlElement<HtmlEl>>, web_sys::EventTarget);
|
|
|
|
//
|
|
|
|
// impl_from_signal_html_element!(Signal<HtmlElement<HtmlEl>>, web_sys::Element);
|
|
|
|
// impl_from_signal_html_element!(ReadSignal<HtmlElement<HtmlEl>>, web_sys::Element);
|
|
|
|
// impl_from_signal_html_element!(RwSignal<HtmlElement<HtmlEl>>, web_sys::Element);
|
|
|
|
// impl_from_signal_html_element!(Memo<HtmlElement<HtmlEl>>, web_sys::Element);
|
|
|
|
//
|
|
|
|
// // From Signal<Option<leptos::html::HTMLElement>> /////////////////////////////////////////
|
|
|
|
//
|
|
|
|
// macro_rules! impl_from_signal_html_element {
|
|
|
|
// ($signal:ty, $ty:ty) => {
|
|
|
|
// impl<HtmlEl> From<$signal> for ElementMaybeSignal<$ty, $ty>
|
|
|
|
// where
|
|
|
|
// HtmlEl: ElementDescriptor + std::ops::Deref<Target = $ty> + Clone,
|
|
|
|
// {
|
|
|
|
// fn from(value: $signal) -> Self {
|
|
|
|
// Self::Dynamic(Signal::derive(move || {
|
|
|
|
// let el: Option<$ty> = value.get().map(|el| el.deref().clone());
|
|
|
|
// el
|
|
|
|
// }))
|
|
|
|
// }
|
|
|
|
// }
|
|
|
|
// };
|
|
|
|
// }
|
|
|
|
//
|
|
|
|
// impl_from_signal_html_element!(Signal<Option<HtmlElement<HtmlEl>>>, web_sys::EventTarget);
|
|
|
|
// impl_from_signal_html_element!(
|
|
|
|
// ReadSignal<Option<HtmlElement<HtmlEl>>>,
|
|
|
|
// web_sys::EventTarget
|
|
|
|
// );
|
|
|
|
// impl_from_signal_html_element!(RwSignal<Option<HtmlElement<HtmlEl>>>, web_sys::EventTarget);
|
|
|
|
// impl_from_signal_html_element!(Memo<Option<HtmlElement<HtmlEl>>>, web_sys::EventTarget);
|
|
|
|
//
|
|
|
|
// impl_from_signal_html_element!(Signal<Option<HtmlElement<HtmlEl>>>, web_sys::Element);
|
|
|
|
// impl_from_signal_html_element!(ReadSignal<Option<HtmlElement<HtmlEl>>>, web_sys::Element);
|
|
|
|
// impl_from_signal_html_element!(RwSignal<Option<HtmlElement<HtmlEl>>>, web_sys::Element);
|
|
|
|
// impl_from_signal_html_element!(Memo<Option<HtmlElement<HtmlEl>>>, web_sys::Element);
|
|
|
|
//
|
|
|
|
// impl_from_signal_html_element!(Signal<Option<HtmlElement<HtmlEl>>>, web_sys::HtmlElement);
|
|
|
|
// impl_from_signal_html_element!(
|
|
|
|
// ReadSignal<Option<HtmlElement<HtmlEl>>>,
|
|
|
|
// web_sys::HtmlElement
|
|
|
|
// );
|
|
|
|
// impl_from_signal_html_element!(RwSignal<Option<HtmlElement<HtmlEl>>>, web_sys::HtmlElement);
|
|
|
|
// impl_from_signal_html_element!(Memo<Option<HtmlElement<HtmlEl>>>, web_sys::HtmlElement);
|