diff --git a/src/core/element_maybe_signal.rs b/src/core/element_maybe_signal.rs index f65423e..5f3b68c 100644 --- a/src/core/element_maybe_signal.rs +++ b/src/core/element_maybe_signal.rs @@ -18,8 +18,8 @@ pub enum ElementMaybeSignal where T: Into + Clone + 'static, { - Static(Option>), - Dynamic(Signal>>), + Static(SendWrapper>), + Dynamic(Signal, LocalStorage>), _Phantom(PhantomData E>), } @@ -28,7 +28,7 @@ where T: Into + Clone + 'static, { fn default() -> Self { - Self::Static(None) + Self::Static(SendWrapper::new(None)) } } @@ -62,28 +62,19 @@ where fn with(&self, f: impl FnOnce(&Option) -> O) -> O { match self { - Self::Static(t) => { - let value = t.as_ref().map(|t| t.clone().take()); + Self::Static(t) => f(&t), + Self::Dynamic(s) => { + let value = s.get(); f(&value) } - Self::Dynamic(s) => s.with(|s| { - let value = s.as_ref().map(|s| s.clone().take()); - f(&value) - }), _ => unreachable!(), } } fn try_with(&self, f: impl FnOnce(&Option) -> O) -> Option { match self { - Self::Static(t) => { - let value = t.as_ref().map(|t| t.clone().take()); - Some(f(&value)) - } - Self::Dynamic(s) => s.try_with(|s| { - let value = s.as_ref().map(|s| s.clone().take()); - f(&value) - }), + Self::Static(t) => Some(f(&t)), + Self::Dynamic(s) => s.try_with(f), _ => unreachable!(), } } @@ -97,28 +88,16 @@ where fn with_untracked(&self, f: impl FnOnce(&Option) -> O) -> O { match self { - Self::Static(t) => { - let value = t.as_ref().map(|t| t.clone().take()); - f(&value) - } - Self::Dynamic(s) => s.with_untracked(|s| { - let value = s.as_ref().map(|s| s.clone().take()); - f(&value) - }), + Self::Static(t) => f(&t), + Self::Dynamic(s) => s.with_untracked(f), _ => unreachable!(), } } fn try_with_untracked(&self, f: impl FnOnce(&Option) -> O) -> Option { match self { - Self::Static(t) => { - let value = t.as_ref().map(|t| t.clone().take()); - Some(f(&value)) - } - Self::Dynamic(s) => s.try_with_untracked(|s| { - let value = s.as_ref().map(|s| s.clone().take()); - f(&value) - }), + Self::Static(t) => Some(f(&t)), + Self::Dynamic(s) => s.try_with_untracked(f), _ => unreachable!(), } } @@ -131,7 +110,7 @@ where T: Into + Clone + 'static, { fn from(value: T) -> Self { - ElementMaybeSignal::Static(Some(SendWrapper::new(value))) + ElementMaybeSignal::Static(SendWrapper::new(Some(value))) } } @@ -140,7 +119,7 @@ where T: Into + Clone + 'static, { fn from(target: Option) -> Self { - ElementMaybeSignal::Static(target.map(SendWrapper::new)) + ElementMaybeSignal::Static(SendWrapper::new(target)) } } @@ -151,7 +130,7 @@ macro_rules! impl_from_deref_option { E: From<$ty2> + 'static, { fn from(value: $ty) -> Self { - Self::Static((*value).clone().map(SendWrapper::new)) + Self::Static(SendWrapper::new((*value).clone())) } } }; @@ -169,9 +148,9 @@ where fn from(target: &'a str) -> Self { cfg_if! { if #[cfg(feature = "ssr")] { let _ = target; - Self::Static(None) + Self::Static(SendWrapper::new(None)) } else { - Self::Static(document().query_selector(target).unwrap_or_default().map(SendWrapper::new)) + Self::Static(SendWrapper::new(document().query_selector(target).unwrap_or_default())) }} } } @@ -194,10 +173,10 @@ macro_rules! impl_from_signal_string { fn from(signal: $ty) -> Self { cfg_if! { if #[cfg(feature = "ssr")] { let _ = signal; - Self::Dynamic(Signal::derive(|| None)) + Self::Dynamic(Signal::derive_local(|| None)) } else { Self::Dynamic( - Signal::derive(move || document().query_selector(&signal.get()).unwrap_or_default().map(SendWrapper::new)), + Signal::derive_local(move || document().query_selector(&signal.get()).unwrap_or_default()), ) }} } @@ -210,8 +189,8 @@ impl_from_signal_string!(ReadSignal); impl_from_signal_string!(RwSignal); impl_from_signal_string!(Memo); -impl_from_signal_string!(Signal<&str>); -impl_from_signal_string!(ReadSignal<&str>); +impl_from_signal_string!(Signal<&'static str>); +impl_from_signal_string!(ReadSignal<&'static str>); impl_from_signal_string!(RwSignal<&'static str>); impl_from_signal_string!(Memo<&'static str>); @@ -230,10 +209,10 @@ macro_rules! impl_from_signal_option { }; } -impl_from_signal_option!(Signal>>); -impl_from_signal_option!(ReadSignal>>); -impl_from_signal_option!(RwSignal>>); -impl_from_signal_option!(Memo>>); +impl_from_signal_option!(Signal, LocalStorage>); +impl_from_signal_option!(ReadSignal, LocalStorage>); +impl_from_signal_option!(RwSignal, LocalStorage>); +impl_from_signal_option!(Memo, LocalStorage>); macro_rules! impl_from_signal { ($ty:ty) => { @@ -242,16 +221,16 @@ macro_rules! impl_from_signal { T: Into + Clone + 'static, { fn from(signal: $ty) -> Self { - Self::Dynamic(Signal::derive(move || Some(signal.get()))) + Self::Dynamic(Signal::derive_local(move || Some(signal.get()))) } } }; } -impl_from_signal!(Signal>); -impl_from_signal!(ReadSignal>); -impl_from_signal!(RwSignal>); -impl_from_signal!(Memo>); +impl_from_signal!(Signal); +impl_from_signal!(ReadSignal); +impl_from_signal!(RwSignal); +impl_from_signal!(Memo); // From NodeRef ////////////////////////////////////////////////////////////// @@ -263,10 +242,10 @@ macro_rules! impl_from_node_ref { R::Output: JsCast + Into<$ty> + Clone + 'static, { fn from(node_ref: NodeRef) -> Self { - Self::Dynamic(Signal::derive(move || { + Self::Dynamic(Signal::derive_local(move || { node_ref.get().map(move |el| { let el: $ty = el.clone().into(); - SendWrapper::new(el) + el }) })) } diff --git a/src/core/elements_maybe_signal.rs b/src/core/elements_maybe_signal.rs index 4a5a153..41a520f 100644 --- a/src/core/elements_maybe_signal.rs +++ b/src/core/elements_maybe_signal.rs @@ -1,12 +1,11 @@ use crate::core::ElementMaybeSignal; use crate::{UseDocument, UseWindow}; use cfg_if::cfg_if; -use leptos::html::{ElementType, HtmlElement}; +use leptos::html::ElementType; use leptos::prelude::wrappers::read::Signal; use leptos::prelude::*; use send_wrapper::SendWrapper; use std::marker::PhantomData; -use std::ops::Deref; use wasm_bindgen::JsCast; /// Used as an argument type to make it easily possible to pass either @@ -20,8 +19,8 @@ pub enum ElementsMaybeSignal where T: Into + Clone + 'static, { - Static(Vec>>), - Dynamic(Signal>>>), + Static(SendWrapper>>), + Dynamic(Signal>, LocalStorage>), _Phantom(PhantomData E>), } @@ -30,7 +29,7 @@ where T: Into + Clone + 'static, { fn default() -> Self { - Self::Static(vec![]) + Self::Static(SendWrapper::new(vec![])) } } @@ -60,9 +59,9 @@ impl With for ElementsMaybeSignal where T: Into + Clone + 'static, { - type Value = Vec>>; + type Value = Vec>; - fn with(&self, f: impl FnOnce(&Vec>>) -> O) -> O { + fn with(&self, f: impl FnOnce(&Vec>) -> O) -> O { match self { Self::Static(v) => f(v), Self::Dynamic(s) => s.with(f), @@ -70,7 +69,7 @@ where } } - fn try_with(&self, f: impl FnOnce(&Vec>>) -> O) -> Option { + fn try_with(&self, f: impl FnOnce(&Vec>) -> O) -> Option { match self { Self::Static(v) => Some(f(v)), Self::Dynamic(s) => s.try_with(f), @@ -83,9 +82,9 @@ impl WithUntracked for ElementsMaybeSignal where T: Into + Clone + 'static, { - type Value = Vec>>; + type Value = Vec>; - fn with_untracked(&self, f: impl FnOnce(&Vec>>) -> O) -> O { + fn with_untracked(&self, f: impl FnOnce(&Vec>) -> O) -> O { match self { Self::Static(t) => f(t), Self::Dynamic(s) => s.with_untracked(f), @@ -93,10 +92,7 @@ where } } - fn try_with_untracked( - &self, - f: impl FnOnce(&Vec>>) -> O, - ) -> Option { + fn try_with_untracked(&self, f: impl FnOnce(&Vec>) -> O) -> Option { match self { Self::Static(t) => Some(f(t)), Self::Dynamic(s) => s.try_with_untracked(f), @@ -112,7 +108,7 @@ where T: Into + Clone + 'static, { fn from(value: T) -> Self { - ElementsMaybeSignal::Static(vec![Some(SendWrapper::new(value))]) + ElementsMaybeSignal::Static(SendWrapper::new(vec![Some(value)])) } } @@ -121,7 +117,7 @@ where T: Into + Clone + 'static, { fn from(target: Option) -> Self { - ElementsMaybeSignal::Static(vec![target.map(SendWrapper::new)]) + ElementsMaybeSignal::Static(SendWrapper::new(vec![target])) } } @@ -132,7 +128,7 @@ macro_rules! impl_from_deref_option { E: From<$ty2> + 'static, { fn from(value: $ty) -> Self { - Self::Static(vec![(*value).clone().map(SendWrapper::new)]) + Self::Static(SendWrapper::new(vec![(*value).clone()])) } } }; @@ -150,18 +146,18 @@ where fn from(target: &'a str) -> Self { cfg_if! { if #[cfg(feature = "ssr")] { let _ = target; - Self::Static(vec![]) + Self::Static(SendWrapper::new(vec![])) } else { if let Ok(node_list) = document().query_selector_all(target) { let mut list = Vec::with_capacity(node_list.length() as usize); for i in 0..node_list.length() { let node = node_list.get(i).expect("checked the range"); - list.push(Some(SendWrapper::new(node))); + list.push(Some(node)); } - Self::Static(list) + Self::Static(SendWrapper::new(list)) } else { - Self::Static(vec![]) + Self::Static(SendWrapper::new(vec![])) } }} } @@ -185,12 +181,12 @@ macro_rules! impl_from_signal_string { fn from(signal: $ty) -> Self { cfg_if! { if #[cfg(feature = "ssr")] { Self::Dynamic( - Signal::derive(move || { + Signal::derive_local(move || { if let Ok(node_list) = document().query_selector_all(&signal.get()) { let mut list = Vec::with_capacity(node_list.length() as usize); for i in 0..node_list.length() { let node = node_list.get(i).expect("checked the range"); - list.push(Some(SendWrapper::new(node))); + list.push(Some(node)); } list } else { @@ -200,7 +196,7 @@ macro_rules! impl_from_signal_string { ) } else { let _ = signal; - Self::Dynamic(Signal::derive(Vec::new)) + Self::Dynamic(Signal::derive_local(Vec::new)) }} } } @@ -212,8 +208,8 @@ impl_from_signal_string!(ReadSignal); impl_from_signal_string!(RwSignal); impl_from_signal_string!(Memo); -impl_from_signal_string!(Signal<&str>); -impl_from_signal_string!(ReadSignal<&str>); +impl_from_signal_string!(Signal<&'static str>); +impl_from_signal_string!(ReadSignal<&'static str>); impl_from_signal_string!(RwSignal<&'static str>); impl_from_signal_string!(Memo<&'static str>); @@ -226,16 +222,16 @@ macro_rules! impl_from_signal_option { T: Into + Clone + 'static, { fn from(signal: $ty) -> Self { - Self::Dynamic(Signal::derive(move || vec![signal.get()])) + Self::Dynamic(Signal::derive_local(move || vec![signal.get()])) } } }; } -impl_from_signal_option!(Signal>>); -impl_from_signal_option!(ReadSignal>>); -impl_from_signal_option!(RwSignal>>); -impl_from_signal_option!(Memo>>); +impl_from_signal_option!(Signal, LocalStorage>); +impl_from_signal_option!(ReadSignal, LocalStorage>); +impl_from_signal_option!(RwSignal, LocalStorage>); +impl_from_signal_option!(Memo, LocalStorage>); macro_rules! impl_from_signal { ($ty:ty) => { @@ -244,16 +240,16 @@ macro_rules! impl_from_signal { T: Into + Clone + 'static, { fn from(signal: $ty) -> Self { - Self::Dynamic(Signal::derive(move || vec![Some(signal.get())])) + Self::Dynamic(Signal::derive_local(move || vec![Some(signal.get())])) } } }; } -impl_from_signal!(Signal>); -impl_from_signal!(ReadSignal>); -impl_from_signal!(RwSignal>); -impl_from_signal!(Memo>); +impl_from_signal!(Signal); +impl_from_signal!(ReadSignal); +impl_from_signal!(RwSignal); +impl_from_signal!(Memo); // From single NodeRef ////////////////////////////////////////////////////////////// @@ -265,10 +261,10 @@ macro_rules! impl_from_node_ref { R::Output: JsCast + Into<$ty> + Clone + 'static, { fn from(node_ref: NodeRef) -> Self { - Self::Dynamic(Signal::derive(move || { + Self::Dynamic(Signal::derive_local(move || { vec![node_ref.get().map(move |el| { let el: $ty = el.clone().into(); - SendWrapper::new(el) + el })] })) } @@ -306,12 +302,9 @@ where T: Into + Clone + 'static, { fn from(target: &[T]) -> Self { - Self::Static( - target - .iter() - .map(|t| Some(SendWrapper::new(t.clone()))) - .collect(), - ) + Self::Static(SendWrapper::new( + target.iter().map(|t| Some(t.clone())).collect(), + )) } } @@ -320,12 +313,7 @@ where T: Into + Clone + 'static, { fn from(target: &[Option]) -> Self { - Self::Static( - target - .iter() - .map(|t| t.clone().map(SendWrapper::new)) - .collect(), - ) + Self::Static(SendWrapper::new(target.iter().map(|t| t.clone()).collect())) } } @@ -334,12 +322,9 @@ where T: Into + Clone + 'static, { fn from(target: Vec) -> Self { - Self::Static( - target - .iter() - .map(|t| Some(SendWrapper::new(t.clone()))) - .collect(), - ) + Self::Static(SendWrapper::new( + target.iter().map(|t| Some(t.clone())).collect(), + )) } } @@ -348,12 +333,7 @@ where T: Into + Clone + 'static, { fn from(target: Vec>) -> Self { - Self::Static( - target - .into_iter() - .map(|t| t.map(SendWrapper::new)) - .collect(), - ) + Self::Static(SendWrapper::new(target.into_iter().map(|t| t).collect())) } } @@ -362,12 +342,9 @@ where T: Into + Clone + 'static, { fn from(target: [T; C]) -> Self { - Self::Static( - target - .into_iter() - .map(|t| Some(SendWrapper::new(t))) - .collect(), - ) + Self::Static(SendWrapper::new( + target.into_iter().map(|t| Some(t)).collect(), + )) } } @@ -376,12 +353,7 @@ where T: Into + Clone + 'static, { fn from(target: [Option; C]) -> Self { - Self::Static( - target - .into_iter() - .map(|t| t.map(SendWrapper::new)) - .collect(), - ) + Self::Static(SendWrapper::new(target.into_iter().collect())) } } @@ -390,30 +362,32 @@ where macro_rules! impl_from_strings_inner { ($el_ty:ty, $str_ty:ty, $target:ident) => { Self::Static( - $target - .iter() - .filter_map(|sel: &$str_ty| -> Option>>> { - cfg_if! { if #[cfg(feature = "ssr")] { - let _ = sel; - None - } else { - use wasm_bindgen::JsCast; - - if let Ok(node_list) = document().query_selector_all(sel) { - let mut list = Vec::with_capacity(node_list.length() as usize); - for i in 0..node_list.length() { - let node: $el_ty = node_list.get(i).expect("checked the range").unchecked_into(); - list.push(Some(SendWrapper::new(node))); - } - - Some(list) - } else { + SendWrapper::new( + $target + .iter() + .filter_map(|sel: &$str_ty| -> Option>> { + cfg_if! { if #[cfg(feature = "ssr")] { + let _ = sel; None - } - }} - }) - .flatten() - .collect(), + } else { + use wasm_bindgen::JsCast; + + if let Ok(node_list) = document().query_selector_all(sel) { + let mut list = Vec::with_capacity(node_list.length() as usize); + for i in 0..node_list.length() { + let node: $el_ty = node_list.get(i).expect("checked the range").unchecked_into(); + list.push(Some(node)); + } + + Some(list) + } else { + None + } + }} + }) + .flatten() + .collect(), + ) ) }; } @@ -452,101 +426,101 @@ impl_from_strings!(web_sys::EventTarget, String); // From signal of vec //////////////////////////////////////////////////////////////// -impl From>>> for ElementsMaybeSignal +impl From, LocalStorage>> for ElementsMaybeSignal where T: Into + Clone + 'static, { - fn from(signal: Signal>>) -> Self { - Self::Dynamic(Signal::derive(move || { + fn from(signal: Signal, LocalStorage>) -> Self { + Self::Dynamic(Signal::derive_local(move || { signal.get().into_iter().map(|t| Some(t)).collect() })) } } -impl From>>>> for ElementsMaybeSignal +impl From>, LocalStorage>> for ElementsMaybeSignal where T: Into + Clone + 'static, { - fn from(target: Signal>>>) -> Self { + fn from(target: Signal>, LocalStorage>) -> Self { Self::Dynamic(target) } } // From multiple signals ////////////////////////////////////////////////////////////// -impl From<&[Signal>]> for ElementsMaybeSignal +impl From<&[Signal]> for ElementsMaybeSignal where T: Into + Clone + 'static, { - fn from(list: &[Signal>]) -> Self { + fn from(list: &[Signal]) -> Self { let list = list.to_vec(); - Self::Dynamic(Signal::derive(move || { + Self::Dynamic(Signal::derive_local(move || { list.iter().map(|t| Some(t.get())).collect() })) } } -impl From<&[Signal>>]> for ElementsMaybeSignal +impl From<&[Signal, LocalStorage>]> for ElementsMaybeSignal where T: Into + Clone + 'static, { - fn from(list: &[Signal>>]) -> Self { + fn from(list: &[Signal, LocalStorage>]) -> Self { let list = list.to_vec(); - Self::Dynamic(Signal::derive(move || { + Self::Dynamic(Signal::derive_local(move || { list.iter().map(|t| t.get()).collect() })) } } -impl From>>> for ElementsMaybeSignal +impl From>> for ElementsMaybeSignal where T: Into + Clone + 'static, { - fn from(list: Vec>>) -> Self { + fn from(list: Vec>) -> Self { let list = list.clone(); - Self::Dynamic(Signal::derive(move || { + Self::Dynamic(Signal::derive_local(move || { list.iter().map(|t| Some(t.get())).collect() })) } } -impl From>>>> for ElementsMaybeSignal +impl From, LocalStorage>>> for ElementsMaybeSignal where T: Into + Clone + 'static, { - fn from(list: Vec>>>) -> Self { + fn from(list: Vec, LocalStorage>>) -> Self { let list = list.clone(); - Self::Dynamic(Signal::derive(move || { + Self::Dynamic(Signal::derive_local(move || { list.iter().map(|t| t.get()).collect() })) } } -impl From<[Signal>; C]> for ElementsMaybeSignal +impl From<[Signal; C]> for ElementsMaybeSignal where T: Into + Clone + 'static, { - fn from(list: [Signal>; C]) -> Self { + fn from(list: [Signal; C]) -> Self { let list = list.to_vec(); - Self::Dynamic(Signal::derive(move || { + Self::Dynamic(Signal::derive_local(move || { list.iter().map(|t| Some(t.get())).collect() })) } } -impl From<[Signal>>; C]> for ElementsMaybeSignal +impl From<[Signal, LocalStorage>; C]> for ElementsMaybeSignal where T: Into + Clone + 'static, { - fn from(list: [Signal>>; C]) -> Self { + fn from(list: [Signal, LocalStorage>; C]) -> Self { let list = list.to_vec(); - Self::Dynamic(Signal::derive(move || { + Self::Dynamic(Signal::derive_local(move || { list.iter().map(|t| t.get()).collect() })) } @@ -556,13 +530,13 @@ where macro_rules! impl_from_multi_node_ref_inner { ($ty:ty, $node_refs:ident) => { - Self::Dynamic(Signal::derive(move || { + Self::Dynamic(Signal::derive_local(move || { $node_refs .iter() .map(|node_ref| { node_ref.get().map(move |el| { let el: $ty = el.clone().into(); - SendWrapper::new(el) + el }) }) .collect() @@ -685,9 +659,11 @@ where fn from(signal: ElementMaybeSignal) -> Self { match signal { ElementMaybeSignal::Dynamic(signal) => { - Self::Dynamic(Signal::derive(move || vec![signal.get()])) + Self::Dynamic(Signal::derive_local(move || vec![signal.get()])) + } + ElementMaybeSignal::Static(el) => { + Self::Static(SendWrapper::new(vec![SendWrapper::take(el)])) } - ElementMaybeSignal::Static(el) => Self::Static(vec![el]), ElementMaybeSignal::_Phantom(_) => unreachable!(), } } diff --git a/src/core/maybe_rw_signal.rs b/src/core/maybe_rw_signal.rs index 3ac2b67..c539d70 100644 --- a/src/core/maybe_rw_signal.rs +++ b/src/core/maybe_rw_signal.rs @@ -1,16 +1,20 @@ use leptos::prelude::*; use std::fmt::Debug; -pub enum MaybeRwSignal +pub enum MaybeRwSignal where T: 'static, + S: Storage, { Static(T), - DynamicRw(Signal, WriteSignal), - DynamicRead(Signal), + DynamicRw(Signal, WriteSignal), + DynamicRead(Signal), } -impl Clone for MaybeRwSignal { +impl Clone for MaybeRwSignal +where + S: Storage, +{ fn clone(&self) -> Self { match self { Self::Static(t) => Self::Static(t.clone()), @@ -20,21 +24,21 @@ impl Clone for MaybeRwSignal { } } -impl Copy for MaybeRwSignal {} +impl Copy for MaybeRwSignal where S: Storage {} -impl From for MaybeRwSignal { - fn from(t: T) -> Self { - Self::Static(t) - } -} - -impl Default for MaybeRwSignal { +impl Default for MaybeRwSignal +where + S: Storage, +{ fn default() -> Self { Self::Static(T::default()) } } -impl Debug for MaybeRwSignal { +impl Debug for MaybeRwSignal +where + S: Storage + Debug, +{ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { Self::Static(t) => f.debug_tuple("Static").field(t).finish(), @@ -44,12 +48,42 @@ impl Debug for MaybeRwSignal { } } -impl From> for MaybeRwSignal { +impl From for MaybeRwSignal +where + SyncStorage: Storage, +{ + fn from(t: T) -> Self { + Self::Static(t) + } +} + +impl FromLocal for MaybeRwSignal +where + LocalStorage: Storage, +{ + fn from_local(value: T) -> Self { + Self::Static(value) + } +} + +impl From> for MaybeRwSignal +where + SyncStorage: Storage, +{ fn from(s: Signal) -> Self { Self::DynamicRead(s) } } +impl FromLocal> for MaybeRwSignal +where + LocalStorage: Storage, +{ + fn from_local(s: Signal) -> Self { + Self::DynamicRead(s) + } +} + impl From> for MaybeRwSignal where T: Send + Sync, @@ -59,6 +93,15 @@ where } } +impl FromLocal> for MaybeRwSignal +where + LocalStorage: Storage, +{ + fn from_local(s: ReadSignal) -> Self { + Self::DynamicRead(s.into()) + } +} + impl From> for MaybeRwSignal where T: Send + Sync, @@ -68,6 +111,15 @@ where } } +impl FromLocal> for MaybeRwSignal +where + LocalStorage: Storage, +{ + fn from_local(s: Memo) -> Self { + Self::DynamicRead(s.into()) + } +} + impl From> for MaybeRwSignal where T: Send + Sync, @@ -78,6 +130,16 @@ where } } +impl FromLocal> for MaybeRwSignal +where + LocalStorage: Storage, +{ + fn from_local(s: RwSignal) -> Self { + let (r, w) = s.split(); + Self::DynamicRw(r.into(), w) + } +} + impl From<(ReadSignal, WriteSignal)> for MaybeRwSignal where T: Send + Sync, @@ -87,18 +149,67 @@ where } } -impl From<(Signal, WriteSignal)> for MaybeRwSignal { +impl FromLocal<(ReadSignal, WriteSignal)> + for MaybeRwSignal +where + LocalStorage: Storage, +{ + fn from_local(s: (ReadSignal, WriteSignal)) -> Self { + Self::DynamicRw(s.0.into(), s.1) + } +} + +impl From<(Signal, WriteSignal)> for MaybeRwSignal +where + T: Send + Sync, +{ fn from(s: (Signal, WriteSignal)) -> Self { Self::DynamicRw(s.0, s.1) } } -impl From<&str> for MaybeRwSignal { +impl FromLocal<(Signal, WriteSignal)> + for MaybeRwSignal +where + LocalStorage: Storage, +{ + fn from_local(s: (Signal, WriteSignal)) -> Self { + Self::DynamicRw(s.0, s.1) + } +} + +impl From<&str> for MaybeRwSignal +where + S: Storage, +{ fn from(s: &str) -> Self { Self::Static(s.to_string()) } } +impl MaybeRwSignal { + pub fn into_signal(self) -> (Signal, WriteSignal) { + match self { + Self::DynamicRead(s) => { + let (r, w) = signal_local(s.get_untracked()); + + Effect::::new(move |_| { + w.update(move |w| { + *w = s.get(); + }); + }); + + (r.into(), w) + } + Self::DynamicRw(r, w) => (r, w), + Self::Static(v) => { + let (r, w) = signal_local(v.clone()); + (Signal::from(r), w) + } + } + } +} + impl MaybeRwSignal where T: Send + Sync, diff --git a/src/core/use_rw_signal.rs b/src/core/use_rw_signal.rs index 73a7e85..c86e722 100644 --- a/src/core/use_rw_signal.rs +++ b/src/core/use_rw_signal.rs @@ -1,21 +1,28 @@ use leptos::prelude::*; -pub enum UseRwSignal { - Separate(Signal, WriteSignal), - Combined(RwSignal), +pub enum UseRwSignal +where + S: Storage, +{ + Separate(Signal, WriteSignal), + Combined(RwSignal), } -impl From> for UseRwSignal { - fn from(s: RwSignal) -> Self { +impl From> for UseRwSignal +where + S: Storage, +{ + fn from(s: RwSignal) -> Self { Self::Combined(s) } } -impl From<(RS, WriteSignal)> for UseRwSignal +impl From<(RS, WriteSignal)> for UseRwSignal where - RS: Into>, + RS: Into>, + S: Storage, { - fn from(s: (RS, WriteSignal)) -> Self { + fn from(s: (RS, WriteSignal)) -> Self { Self::Separate(s.0.into(), s.1) } } @@ -29,15 +36,30 @@ where } } -impl Clone for UseRwSignal { +impl Default for UseRwSignal +where + T: Default, +{ + fn default() -> Self { + Self::Combined(Default::default()) + } +} + +impl Clone for UseRwSignal +where + S: Storage, +{ fn clone(&self) -> Self { *self } } -impl Copy for UseRwSignal {} +impl Copy for UseRwSignal where S: Storage {} -impl DefinedAt for UseRwSignal { +impl DefinedAt for UseRwSignal +where + S: Storage, +{ fn defined_at(&self) -> Option<&'static std::panic::Location<'static>> { match self { Self::Combined(s) => s.defined_at(), @@ -47,9 +69,12 @@ impl DefinedAt for UseRwSignal { } } -impl With for UseRwSignal +impl With for UseRwSignal where - T: Send + Sync, + RwSignal: With, + Signal: With, + ReadSignal: With, + S: Storage, { type Value = T; @@ -68,9 +93,12 @@ where } } -impl WithUntracked for UseRwSignal +impl WithUntracked for UseRwSignal where - T: Send + Sync, + RwSignal: WithUntracked, + Signal: WithUntracked, + ReadSignal: WithUntracked, + S: Storage, { type Value = T; @@ -89,7 +117,12 @@ where } } -impl Set for UseRwSignal { +impl Set for UseRwSignal +where + RwSignal: Set, + WriteSignal: Set, + S: Storage, +{ type Value = T; fn set(&self, new_value: T) { @@ -107,7 +140,12 @@ impl Set for UseRwSignal { } } -impl Update for UseRwSignal { +impl Update for UseRwSignal +where + RwSignal: Update, + WriteSignal: Update, + S: Storage, +{ type Value = T; fn update(&self, f: impl FnOnce(&mut T)) { diff --git a/src/lib.rs b/src/lib.rs index 617c0b3..aaf827c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -68,7 +68,7 @@ mod use_preferred_dark; mod use_raf_fn; mod use_resize_observer; mod use_scroll; -// mod use_service_worker; +mod use_service_worker; mod use_sorted; mod use_supported; mod use_throttle_fn; @@ -134,7 +134,7 @@ pub use use_preferred_dark::*; pub use use_raf_fn::*; pub use use_resize_observer::*; pub use use_scroll::*; -// pub use use_service_worker::*; +pub use use_service_worker::*; pub use use_sorted::*; pub use use_supported::*; pub use use_throttle_fn::*; diff --git a/src/on_click_outside.rs b/src/on_click_outside.rs index db5e2d9..d3868c9 100644 --- a/src/on_click_outside.rs +++ b/src/on_click_outside.rs @@ -149,7 +149,7 @@ where let ignore = ignore.get_untracked(); ignore.into_iter().flatten().any(|element| { - let element: web_sys::EventTarget = element.take().into(); + let element: web_sys::EventTarget = element.into(); event_target::(event) == element || event.composed_path().includes(element.as_ref(), 0) diff --git a/src/storage/use_local_storage.rs b/src/storage/use_local_storage.rs index 0009439..9f3a66b 100644 --- a/src/storage/use_local_storage.rs +++ b/src/storage/use_local_storage.rs @@ -15,7 +15,7 @@ pub fn use_local_storage( key: impl AsRef, ) -> (Signal, WriteSignal, impl Fn() + Clone) where - T: Clone + Default + PartialEq + Send + Sync, + T: Clone + Default + PartialEq + Send + Sync + 'static, C: Encoder + Decoder, { use_storage_with_options::( diff --git a/src/storage/use_session_storage.rs b/src/storage/use_session_storage.rs index cce1d65..bbf5777 100644 --- a/src/storage/use_session_storage.rs +++ b/src/storage/use_session_storage.rs @@ -14,7 +14,7 @@ pub fn use_session_storage( key: impl AsRef, ) -> (Signal, WriteSignal, impl Fn() + Clone) where - T: Clone + Default + PartialEq + Send + Sync, + T: Clone + Default + PartialEq + Send + Sync + 'static, C: Encoder + Decoder, { use_storage_with_options::( diff --git a/src/storage/use_storage.rs b/src/storage/use_storage.rs index 93a26d1..96a2be2 100644 --- a/src/storage/use_storage.rs +++ b/src/storage/use_storage.rs @@ -152,7 +152,7 @@ pub fn use_storage( key: impl AsRef, ) -> (Signal, WriteSignal, impl Fn() + Clone) where - T: Default + Clone + PartialEq + Send + Sync, + T: Default + Clone + PartialEq + Send + Sync + 'static, C: Encoder + Decoder, { use_storage_with_options::(storage_type, key, UseStorageOptions::default()) @@ -203,7 +203,7 @@ where // Get storage API let storage = storage_type .into_storage() - .map_err(|e| UseStorageError::StorageNotAvailable(SendWrapper::new(e))) + .map_err(UseStorageError::StorageNotAvailable) .and_then(|s| s.ok_or(UseStorageError::StorageReturnedNone)); let storage = handle_error(&on_error, storage); @@ -227,7 +227,7 @@ where ) .expect("failed to create custom storage event"), ) - .map_err(|e| UseStorageError::NotifyItemChangedFailed(SendWrapper::new(e))); + .map_err(UseStorageError::NotifyItemChangedFailed); let _ = handle_error(&on_error, result); }) } @@ -246,7 +246,7 @@ where // Get directly from storage let result = storage .get_item(&key) - .map_err(|e| UseStorageError::GetItemFailed(SendWrapper::new(e))); + .map_err(UseStorageError::GetItemFailed); handle_error(&on_error, result) }) .unwrap_or_default() // Drop handled Err(()) @@ -314,9 +314,9 @@ where .map_err(|e| UseStorageError::ItemCodecError(CodecError::Encode(e))) .and_then(|enc_value| { // Set storage -- sends a global event - storage.set_item(&key, &enc_value).map_err(|e| { - UseStorageError::SetItemFailed(SendWrapper::new(e)) - }) + storage + .set_item(&key, &enc_value) + .map_err(UseStorageError::SetItemFailed) }); let result = handle_error(&on_error, result); // Send internal storage event @@ -329,18 +329,19 @@ where ); } - // TODO: solve for 0.7 - // // Fetch initial value - // if delay_during_hydration && leptos::leptos_dom::HydrationCtx::is_hydrating() { - // request_animation_frame(fetch_from_storage.clone()); - // } else { - // fetch_from_storage(); - // } - request_animation_frame({ - let fetch_from_storage = fetch_from_storage.clone(); - #[allow(clippy::redundant_closure)] - move || fetch_from_storage() - }); + if delay_during_hydration + && Owner::current_shared_context() + .map(|sc| sc.during_hydration()) + .unwrap_or_default() + { + request_animation_frame({ + let fetch_from_storage = fetch_from_storage.clone(); + #[allow(clippy::redundant_closure)] + move || fetch_from_storage() + }); + } else { + fetch_from_storage(); + } if listen_to_storage_changes { let check_key = key.as_ref().to_owned(); @@ -378,7 +379,7 @@ where // Delete directly from storage let result = storage .remove_item(&key) - .map_err(|e| UseStorageError::RemoveItemFailed(SendWrapper::new(e))); + .map_err(|e| UseStorageError::RemoveItemFailed(e)); let _ = handle_error(&on_error, result); notify.trigger(); dispatch_storage_event(); @@ -394,17 +395,17 @@ where #[derive(Error, Debug)] pub enum UseStorageError { #[error("storage not available")] - StorageNotAvailable(SendWrapper), + StorageNotAvailable(JsValue), #[error("storage not returned from window")] StorageReturnedNone, #[error("failed to get item")] - GetItemFailed(SendWrapper), + GetItemFailed(JsValue), #[error("failed to set item")] - SetItemFailed(SendWrapper), + SetItemFailed(JsValue), #[error("failed to delete item")] - RemoveItemFailed(SendWrapper), + RemoveItemFailed(JsValue), #[error("failed to notify item changed")] - NotifyItemChangedFailed(SendWrapper), + NotifyItemChangedFailed(JsValue), #[error("failed to encode / decode item value")] ItemCodecError(CodecError), } @@ -413,7 +414,7 @@ pub enum UseStorageError { #[derive(DefaultBuilder)] pub struct UseStorageOptions where - T: 'static, + T: Send + Sync + 'static, { // Callback for when an error occurs #[builder(skip)] @@ -441,7 +442,10 @@ fn handle_error( result.map_err(|err| (on_error)(err)) } -impl Default for UseStorageOptions { +impl Default for UseStorageOptions +where + T: Send + Sync + 'static, +{ fn default() -> Self { Self { on_error: Arc::new(|_err| ()), @@ -453,7 +457,10 @@ impl Default for UseStorageOptions { } } -impl UseStorageOptions { +impl UseStorageOptions +where + T: Send + Sync + 'static, +{ /// Optional callback whenever an error occurs. pub fn on_error( self, diff --git a/src/use_breakpoints.rs b/src/use_breakpoints.rs index fee58fe..e2f8106 100644 --- a/src/use_breakpoints.rs +++ b/src/use_breakpoints.rs @@ -184,7 +184,10 @@ macro_rules! impl_cmp_reactively { }; } -impl UseBreakpointsReturn { +impl UseBreakpointsReturn +where + K: Eq + Hash + Debug + Clone + Send + Sync + 'static, +{ fn match_(query: &str) -> bool { if let Ok(Some(query_list)) = use_window().match_media(query) { return query_list.matches(); diff --git a/src/use_broadcast_channel.rs b/src/use_broadcast_channel.rs index 9abd612..9f09186 100644 --- a/src/use_broadcast_channel.rs +++ b/src/use_broadcast_channel.rs @@ -4,7 +4,6 @@ use crate::{ use codee::{CodecError, Decoder, Encoder}; use leptos::ev::messageerror; use leptos::prelude::*; -use send_wrapper::SendWrapper; use thiserror::Error; use wasm_bindgen::JsValue; @@ -89,9 +88,9 @@ where let is_supported = use_supported(|| js!("BroadcastChannel" in &window())); let (is_closed, set_closed) = signal(false); - let (channel, set_channel) = signal(None::>); + let (channel, set_channel) = signal_local(None::); let (message, set_message) = signal(None::); - let (error, set_error) = signal( + let (error, set_error) = signal_local( None::>::Error, >::Error>>, ); @@ -103,9 +102,7 @@ where channel .post_message(&msg.into()) .map_err(|err| { - set_error.set(Some(UseBroadcastChannelError::PostMessage( - SendWrapper::new(err), - ))) + set_error.set(Some(UseBroadcastChannelError::PostMessage(err))) }) .ok(); } @@ -130,7 +127,7 @@ where if is_supported.get_untracked() { let channel_val = web_sys::BroadcastChannel::new(name).ok(); - set_channel.set(channel_val.clone().map(SendWrapper::new)); + set_channel.set(channel_val.clone()); if let Some(channel) = channel_val { let _ = use_event_listener_with_options( @@ -157,9 +154,7 @@ where channel.clone(), messageerror, move |event| { - set_error.set(Some(UseBroadcastChannelError::MessageEvent( - SendWrapper::new(event), - ))); + set_error.set(Some(UseBroadcastChannelError::MessageEvent(event))); }, UseEventListenerOptions::default().passive(true), ); @@ -186,17 +181,17 @@ where /// Return type of [`use_broadcast_channel`]. pub struct UseBroadcastChannelReturn where - T: 'static, + T: Send + Sync + 'static, PFn: Fn(&T) + Clone, CFn: Fn() + Clone, - E: 'static, - D: 'static, + E: Send + Sync + 'static, + D: Send + Sync + 'static, { /// `true` if this browser supports `BroadcastChannel`s. pub is_supported: Signal, /// The broadcast channel that is wrapped by this function - pub channel: Signal>>, + pub channel: Signal, LocalStorage>, /// Latest message received from the channel pub message: Signal>, @@ -208,7 +203,7 @@ where pub close: CFn, /// Latest error as reported by the `messageerror` event. - pub error: Signal>>, + pub error: Signal>, LocalStorage>, /// Wether the channel is closed pub is_closed: Signal, @@ -217,9 +212,9 @@ where #[derive(Debug, Error)] pub enum UseBroadcastChannelError { #[error("failed to post message")] - PostMessage(SendWrapper), + PostMessage(JsValue), #[error("channel message error")] - MessageEvent(SendWrapper), + MessageEvent(web_sys::MessageEvent), #[error("failed to (de)encode value")] Codec(CodecError), #[error("received value is not a string")] diff --git a/src/use_cookie.rs b/src/use_cookie.rs index 11c3b9f..f1261e5 100644 --- a/src/use_cookie.rs +++ b/src/use_cookie.rs @@ -143,7 +143,7 @@ use std::sync::Arc; pub fn use_cookie(cookie_name: &str) -> (Signal>, WriteSignal>) where C: Encoder + Decoder, - T: Clone + Send + Sync, + T: Clone + Send + Sync + 'static, { use_cookie_with_options::(cookie_name, UseCookieOptions::default()) } @@ -155,7 +155,7 @@ pub fn use_cookie_with_options( ) -> (Signal>, WriteSignal>) where C: Encoder + Decoder, - T: Clone + Send + Sync, + T: Clone + Send + Sync + 'static, { let UseCookieOptions { max_age, @@ -363,31 +363,38 @@ where #[cfg(feature = "ssr")] { if !readonly { - create_isomorphic_effect(move |_| { - let value = cookie - .with(|cookie| { - cookie.as_ref().map(|cookie| { - C::encode(cookie) - .map_err(|err| on_error(CodecError::Encode(err))) - .ok() + Effect::new_isomorphic({ + let cookie_name = cookie_name.to_owned(); + + move |_| { + let domain = domain.clone(); + let path = path.clone(); + + let value = cookie + .with(|cookie| { + cookie.as_ref().map(|cookie| { + C::encode(cookie) + .map_err(|err| on_error(CodecError::Encode(err))) + .ok() + }) }) - }) - .flatten(); - jar.update_value(|jar| { - write_server_cookie( - cookie_name, - value, - jar, - max_age, - expires, - domain, - path, - same_site, - secure, - http_only, - ssr_set_cookie, - ) - }); + .flatten(); + jar.update_value(|jar| { + write_server_cookie( + &cookie_name, + value, + jar, + max_age, + expires, + domain, + path, + same_site, + secure, + http_only, + Arc::clone(&ssr_set_cookie), + ) + }); + } }); } } diff --git a/src/use_cycle_list.rs b/src/use_cycle_list.rs index 2a38b3b..5c1d3ce 100644 --- a/src/use_cycle_list.rs +++ b/src/use_cycle_list.rs @@ -173,7 +173,7 @@ where #[derive(DefaultBuilder)] pub struct UseCycleListOptions where - T: Clone + PartialEq + 'static, + T: Clone + PartialEq + Send + Sync + 'static, { /// The initial value of the state. Can be a Signal. If none is provided the first entry /// of the list will be used. @@ -191,7 +191,7 @@ where impl Default for UseCycleListOptions where - T: Clone + PartialEq + 'static, + T: Clone + PartialEq + Send + Sync + 'static, { fn default() -> Self { Self { @@ -205,7 +205,7 @@ where /// Return type of [`use_cycle_list`]. pub struct UseCycleListReturn where - T: Clone + PartialEq + 'static, + T: Clone + PartialEq + Send + Sync + 'static, SetFn: Fn(usize) -> T + Clone, NextFn: Fn() + Clone, PrevFn: Fn() + Clone, diff --git a/src/use_device_orientation.rs b/src/use_device_orientation.rs index f02ee54..051a10d 100644 --- a/src/use_device_orientation.rs +++ b/src/use_device_orientation.rs @@ -68,8 +68,10 @@ pub fn use_device_orientation() -> UseDeviceOrientationReturn { .once(false), ); - let cleanup = SendWrapper::new(cleanup); - on_cleanup(move || cleanup()); + on_cleanup({ + let cleanup = SendWrapper::new(cleanup); + move || cleanup() + }); } }} diff --git a/src/use_display_media.rs b/src/use_display_media.rs index a732f86..32db705 100644 --- a/src/use_display_media.rs +++ b/src/use_display_media.rs @@ -3,7 +3,6 @@ use cfg_if::cfg_if; use default_struct_builder::DefaultBuilder; use leptos::prelude::wrappers::read::Signal; use leptos::prelude::*; -use send_wrapper::SendWrapper; use wasm_bindgen::{JsCast, JsValue}; /// Reactive [`mediaDevices.getDisplayMedia`](https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/getDisplayMedia) streaming. @@ -56,8 +55,7 @@ pub fn use_display_media_with_options( let (enabled, set_enabled) = enabled.into_signal(); - let (stream, set_stream) = - signal(None::, SendWrapper>>); + let (stream, set_stream) = signal_local(None::>); let _start = move || async move { cfg_if! { if #[cfg(not(feature = "ssr"))] { @@ -65,10 +63,7 @@ pub fn use_display_media_with_options( return; } - let stream = create_media(audio) - .await - .map(SendWrapper::new) - .map_err(SendWrapper::new); + let stream = create_media(audio).await; set_stream.update(|s| *s = Some(stream)); } else { @@ -181,7 +176,7 @@ where /// Initially this is `None` until `start` resolved successfully. /// In case the stream couldn't be started, for example because the user didn't grant permission, /// this has the value `Some(Err(...))`. - pub stream: Signal, SendWrapper>>>, + pub stream: Signal>, LocalStorage>, /// Starts the screen streaming. Triggers the ask for permission if not already granted. pub start: StartFn, diff --git a/src/use_draggable.rs b/src/use_draggable.rs index 43f4893..e0d0d72 100644 --- a/src/use_draggable.rs +++ b/src/use_draggable.rs @@ -5,7 +5,6 @@ use leptos::ev::{pointerdown, pointermove, pointerup}; use leptos::prelude::diagnostics::SpecialNonReactiveZone; use leptos::prelude::wrappers::read::Signal; use leptos::prelude::*; -use send_wrapper::SendWrapper; use std::marker::PhantomData; use std::sync::Arc; use wasm_bindgen::JsCast; @@ -93,12 +92,11 @@ where let target = target.into(); let dragging_handle = if let Some(handle) = handle { - // let handle = Signal::derive(|| SendWrapper::new(handle)); let handle: ElementMaybeSignal<_, _> = handle.into(); - Signal::derive(move || handle.get().map(|handle| SendWrapper::new(handle.into()))) + Signal::derive_local(move || handle.get().map(|handle| handle.into())) } else { let target = target.clone(); - Signal::derive(move || target.get().map(|target| SendWrapper::new(target.into()))) + Signal::derive_local(move || target.get().map(|target| target.into())) }; let (position, set_position) = initial_value.into_signal(); diff --git a/src/use_drop_zone.rs b/src/use_drop_zone.rs index e88b345..d64a907 100644 --- a/src/use_drop_zone.rs +++ b/src/use_drop_zone.rs @@ -3,7 +3,6 @@ use cfg_if::cfg_if; use default_struct_builder::DefaultBuilder; use leptos::prelude::wrappers::read::Signal; use leptos::prelude::*; -use send_wrapper::SendWrapper; use std::fmt::{Debug, Formatter}; use std::sync::Arc; @@ -74,7 +73,7 @@ where T: Into + Clone + 'static, { let (is_over_drop_zone, set_over_drop_zone) = signal(false); - let (files, set_files) = signal(Vec::>::new()); + let (files, set_files) = signal_local(Vec::::new()); #[cfg(not(feature = "ssr"))] { @@ -95,7 +94,7 @@ where .map(|f| js_sys::Array::from(&f).to_vec()) .unwrap_or_default() .into_iter() - .map(|f| SendWrapper::new(web_sys::File::from(f))) + .map(web_sys::File::from) .collect(); set_files.update(move |f| *f = files); @@ -113,11 +112,7 @@ where let _z = SpecialNonReactiveZone::enter(); on_enter(UseDropZoneEvent { - files: files - .get_untracked() - .into_iter() - .map(SendWrapper::take) - .collect(), + files: files.get_untracked().into_iter().collect(), event, }); }); @@ -130,11 +125,7 @@ where let _z = SpecialNonReactiveZone::enter(); on_over(UseDropZoneEvent { - files: files - .get_untracked() - .into_iter() - .map(SendWrapper::take) - .collect(), + files: files.get_untracked().into_iter().collect(), event, }); }); @@ -152,11 +143,7 @@ where let _z = SpecialNonReactiveZone::enter(); on_leave(UseDropZoneEvent { - files: files - .get_untracked() - .into_iter() - .map(SendWrapper::take) - .collect(), + files: files.get_untracked().into_iter().collect(), event, }); }); @@ -172,11 +159,7 @@ where let _z = SpecialNonReactiveZone::enter(); on_drop(UseDropZoneEvent { - files: files - .get_untracked() - .into_iter() - .map(SendWrapper::take) - .collect(), + files: files.get_untracked().into_iter().collect(), event, }); }); @@ -231,7 +214,7 @@ pub struct UseDropZoneEvent { /// Return type of [`use_drop_zone`]. pub struct UseDropZoneReturn { /// Files being handled - pub files: Signal>>, + pub files: Signal, LocalStorage>, /// Whether the files (dragged by the pointer) are over the drop zone pub is_over_drop_zone: Signal, } diff --git a/src/use_event_listener.rs b/src/use_event_listener.rs index 7dbc150..463cc76 100644 --- a/src/use_event_listener.rs +++ b/src/use_event_listener.rs @@ -188,8 +188,10 @@ where cleanup_prev_element(); }; - let cleanup_stop = SendWrapper::new(stop.clone()); - on_cleanup(move || cleanup_stop()); + on_cleanup({ + let stop = SendWrapper::new(stop.clone()); + move || stop() + }); stop } diff --git a/src/use_event_source.rs b/src/use_event_source.rs index 9909c4f..2dc5f0f 100644 --- a/src/use_event_source.rs +++ b/src/use_event_source.rs @@ -4,7 +4,6 @@ use codee::Decoder; use default_struct_builder::DefaultBuilder; use leptos::prelude::diagnostics::SpecialNonReactiveZone; use leptos::prelude::*; -use send_wrapper::SendWrapper; use std::marker::PhantomData; use std::sync::atomic::{AtomicBool, AtomicU32}; use std::sync::Arc; @@ -148,11 +147,11 @@ where let url = url.to_owned(); - let (event, set_event) = signal(None::>); + let (event, set_event) = signal_local(None::); let (data, set_data) = signal(None::); let (ready_state, set_ready_state) = signal(ConnectionReadyState::Closed); - let (event_source, set_event_source) = signal(None::>); - let (error, set_error) = signal(None::>); + let (event_source, set_event_source) = signal_local(None::); + let (error, set_error) = signal_local(None::>); let explicitly_closed = Arc::new(AtomicBool::new(false)); let retried = Arc::new(AtomicU32::new(0)); @@ -200,7 +199,7 @@ where set_ready_state.set(ConnectionReadyState::Connecting); - set_event_source.set(Some(SendWrapper::new(es.clone()))); + set_event_source.set(Some(es.clone())); let on_open = Closure::wrap(Box::new(move |_: web_sys::Event| { set_ready_state.set(ConnectionReadyState::Open); @@ -217,7 +216,7 @@ where move |e: web_sys::Event| { set_ready_state.set(ConnectionReadyState::Closed); - set_error.set(Some(UseEventSourceError::Event(SendWrapper::new(e)))); + set_error.set(Some(UseEventSourceError::Event(e))); // only reconnect if EventSource isn't reconnecting by itself // this is the case when the connection is closed (readyState is 2) @@ -262,7 +261,7 @@ where es.clone(), leptos::ev::Custom::::new(event_name), move |e| { - set_event.set(Some(SendWrapper::new(e.clone()))); + set_event.set(Some(e.clone())); let data_string = js!(e["data"]).ok().and_then(|d| d.as_string()); set_data_from_string(data_string); }, @@ -373,10 +372,10 @@ where pub ready_state: Signal, /// The latest named event - pub event: Signal>>, + pub event: Signal, LocalStorage>, /// The current error - pub error: Signal>>, + pub error: Signal>, LocalStorage>, /// (Re-)Opens the `EventSource` connection /// If the current one is active, will close it before opening a new one. @@ -386,13 +385,13 @@ where pub close: CloseFn, /// The `EventSource` instance - pub event_source: Signal>>, + pub event_source: Signal, LocalStorage>, } #[derive(Error, Debug)] pub enum UseEventSourceError { #[error("Error event: {0:?}")] - Event(SendWrapper), + Event(web_sys::Event), #[error("Error decoding value")] Deserialize(Err), diff --git a/src/use_geolocation.rs b/src/use_geolocation.rs index 5fbe920..8b6ff05 100644 --- a/src/use_geolocation.rs +++ b/src/use_geolocation.rs @@ -2,7 +2,6 @@ use cfg_if::cfg_if; use default_struct_builder::DefaultBuilder; use leptos::prelude::wrappers::read::Signal; use leptos::prelude::*; -use send_wrapper::SendWrapper; /// Reactive [Geolocation API](https://developer.mozilla.org/en-US/docs/Web/API/Geolocation_API). /// It allows the user to provide their location to web applications if they so desire. For privacy reasons, @@ -44,8 +43,8 @@ pub fn use_geolocation_with_options( options: UseGeolocationOptions, ) -> UseGeolocationReturn { let (located_at, set_located_at) = signal(None::); - let (error, set_error) = signal(None::>); - let (coords, set_coords) = signal(None::>); + let (error, set_error) = signal_local(None::); + let (coords, set_coords) = signal_local(None::); cfg_if! { if #[cfg(feature = "ssr")] { let resume = || (); @@ -62,12 +61,12 @@ pub fn use_geolocation_with_options( let update_position = move |position: web_sys::Position| { set_located_at.set(Some(position.timestamp())); - set_coords.set(Some(SendWrapper::new(position.coords()))); + set_coords.set(Some(position.coords())); set_error.set(None); }; let on_error = move |err: web_sys::PositionError| { - set_error.set(Some(SendWrapper::new(err))); + set_error.set(Some(err)); }; let watch_handle = Arc::new(Mutex::new(None::)); @@ -203,13 +202,13 @@ where { /// The coordinates of the current device like latitude and longitude. /// See [`GeolocationCoordinates`](https://developer.mozilla.org/en-US/docs/Web/API/GeolocationCoordinates).. - pub coords: Signal>>, + pub coords: Signal, LocalStorage>, /// The timestamp of the current coordinates. pub located_at: Signal>, /// The last error received from `navigator.geolocation`. - pub error: Signal>>, + pub error: Signal, LocalStorage>, /// Resume the geolocation watch. pub resume: ResumeFn, diff --git a/src/use_infinite_scroll.rs b/src/use_infinite_scroll.rs index 4059c64..e55642f 100644 --- a/src/use_infinite_scroll.rs +++ b/src/use_infinite_scroll.rs @@ -9,7 +9,6 @@ use gloo_timers::future::sleep; use leptos::prelude::diagnostics::SpecialNonReactiveZone; use leptos::prelude::wrappers::read::Signal; use leptos::prelude::*; -use send_wrapper::SendWrapper; use std::future::Future; use std::sync::Arc; use std::time::Duration; @@ -111,20 +110,18 @@ where let (is_loading, set_loading) = signal(false); let el = el.into(); - let observed_element = Signal::derive(move || { + let observed_element = Signal::derive_local(move || { let el = el.get(); el.map(|el| { let el = el.into(); if el.is_instance_of::() || el.is_instance_of::() { - SendWrapper::new( - document() - .document_element() - .expect("document element not found"), - ) + document() + .document_element() + .expect("document element not found") } else { - SendWrapper::new(el) + el } }) }); diff --git a/src/use_intersection_observer.rs b/src/use_intersection_observer.rs index 5f24990..7acc128 100644 --- a/src/use_intersection_observer.rs +++ b/src/use_intersection_observer.rs @@ -175,7 +175,7 @@ where .expect("failed to create IntersectionObserver"); for target in targets.iter().flatten() { - let target: web_sys::Element = target.clone().take().into(); + let target: web_sys::Element = target.clone().into(); obs.observe(&target); } diff --git a/src/use_interval_fn.rs b/src/use_interval_fn.rs index 4fab709..e21fed4 100644 --- a/src/use_interval_fn.rs +++ b/src/use_interval_fn.rs @@ -141,8 +141,10 @@ where on_cleanup(stop_watch); } - let pause_cleanup = SendWrapper::new(pause.clone()); - on_cleanup(move || pause_cleanup()); + on_cleanup({ + let pause = SendWrapper::new(pause.clone()); + move || pause() + }); Pausable { is_active: is_active.into(), diff --git a/src/use_intl_number_format.rs b/src/use_intl_number_format.rs index ca95fd0..1c1bb63 100644 --- a/src/use_intl_number_format.rs +++ b/src/use_intl_number_format.rs @@ -6,7 +6,6 @@ use cfg_if::cfg_if; use default_struct_builder::DefaultBuilder; use leptos::prelude::wrappers::read::Signal; use leptos::prelude::*; -use send_wrapper::SendWrapper; use std::fmt::Display; use wasm_bindgen::{JsCast, JsValue}; @@ -168,7 +167,7 @@ pub fn use_intl_number_format(options: UseIntlNumberFormatOptions) -> UseIntlNum ); UseIntlNumberFormatReturn { - js_intl_number_format: SendWrapper::new(number_format), + js_intl_number_format: number_format, } }} } @@ -769,14 +768,14 @@ cfg_if! { if #[cfg(feature = "ssr")] { /// Return type of [`use_intl_number_format`]. pub struct UseIntlNumberFormatReturn { /// The instance of [`Intl.NumberFormat`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/NumberFormat). - pub js_intl_number_format: SendWrapper, + pub js_intl_number_format: js_sys::Intl::NumberFormat, } }} impl UseIntlNumberFormatReturn { /// Formats a number according to the [locale and formatting options](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/NumberFormat/NumberFormat#parameters) of this `Intl.NumberFormat` object. /// See [`use_intl_number_format`] for more information. - pub fn format(&self, number: impl Into>) -> Signal + pub fn format(&self, number: impl Into>) -> Signal where N: Clone + Display + Send + Sync + 'static, js_sys::Number: From, @@ -784,13 +783,13 @@ impl UseIntlNumberFormatReturn { let number = number.into(); cfg_if! { if #[cfg(feature = "ssr")] { - Signal::derive(move || { + Signal::derive_local(move || { format!("{}", number.get()) }) } else { let number_format = self.js_intl_number_format.clone(); - Signal::derive(move || { + Signal::derive_local(move || { if let Ok(result) = number_format .format() .call1(&number_format, &js_sys::Number::from(number.get()).into()) @@ -853,7 +852,7 @@ impl UseIntlNumberFormatReturn { &self, start: impl Into>, end: impl Into>, - ) -> Signal + ) -> Signal where NStart: Clone + Display + Send + Sync + 'static, NEnd: Clone + Display + Send + Sync + 'static, @@ -864,13 +863,13 @@ impl UseIntlNumberFormatReturn { let end = end.into(); cfg_if! { if #[cfg(feature = "ssr")] { - Signal::derive(move || { + Signal::derive_local(move || { format!("{} - {}", start.get(), end.get()) }) } else { let number_format = self.js_intl_number_format.clone(); - Signal::derive(move || { + Signal::derive_local(move || { if let Ok(function) = js!(number_format["formatRange"]) { let function = function.unchecked_into::(); diff --git a/src/use_mutation_observer.rs b/src/use_mutation_observer.rs index ceabaa4..8f223c4 100644 --- a/src/use_mutation_observer.rs +++ b/src/use_mutation_observer.rs @@ -136,7 +136,7 @@ where .expect("failed to create MutationObserver"); for target in targets.iter().flatten() { - let target: web_sys::Element = target.clone().take().into(); + let target: web_sys::Element = target.clone().into(); let _ = obs.observe_with_options(&target, &options.clone().into()); } diff --git a/src/use_raf_fn.rs b/src/use_raf_fn.rs index 45fce03..728f8f5 100644 --- a/src/use_raf_fn.rs +++ b/src/use_raf_fn.rs @@ -138,8 +138,10 @@ pub fn use_raf_fn_with_options( resume(); } - let pause_cleanup = send_wrapper::SendWrapper::new(pause.clone()); - on_cleanup(move || pause_cleanup()); + on_cleanup({ + let pause = send_wrapper::SendWrapper::new(pause.clone()); + move || pause() + }); Pausable { resume, diff --git a/src/use_resize_observer.rs b/src/use_resize_observer.rs index c6d96e1..86c1a15 100644 --- a/src/use_resize_observer.rs +++ b/src/use_resize_observer.rs @@ -138,7 +138,7 @@ where .expect("failed to create ResizeObserver"); for target in targets.iter().flatten() { - let target: web_sys::Element = target.clone().take().into(); + let target: web_sys::Element = target.clone().into(); obs.observe_with_options(&target, &options.clone().into()); } observer.replace(Some(obs)); diff --git a/src/use_scroll.rs b/src/use_scroll.rs index b00dec2..a1f28c6 100644 --- a/src/use_scroll.rs +++ b/src/use_scroll.rs @@ -221,8 +221,6 @@ where let set_y = |_| {}; let measure = || {}; } else { - use send_wrapper::SendWrapper; - let signal = element.into(); let behavior = options.behavior; @@ -372,9 +370,9 @@ where let target = { let signal = signal.clone(); - Signal::derive(move || { + Signal::derive_local(move || { let element = signal.get(); - element.map(|element| SendWrapper::new(element.into().unchecked_into::())) + element.map(|element| element.into().unchecked_into::()) }) }; @@ -394,14 +392,14 @@ where let _ = use_event_listener_with_options::< _, - Signal>>, + Signal, LocalStorage>, web_sys::EventTarget, _, >(target, ev::scroll, handler, options.event_listener_options); } else { let _ = use_event_listener_with_options::< _, - Signal>>, + Signal, LocalStorage>, web_sys::EventTarget, _, >( @@ -414,7 +412,7 @@ where let _ = use_event_listener_with_options::< _, - Signal>>, + Signal, LocalStorage>, web_sys::EventTarget, _, >( diff --git a/src/use_service_worker.rs b/src/use_service_worker.rs index 76958b1..4fed646 100644 --- a/src/use_service_worker.rs +++ b/src/use_service_worker.rs @@ -146,7 +146,7 @@ pub fn use_service_worker_with_options( check_for_update: move || { registration.with(|reg| { if let Ok(reg) = reg { - update_sw.dispatch(reg.clone()) + update_sw.dispatch(reg.clone()); } }) }, @@ -246,7 +246,7 @@ fn create_action_update() -> Action< SendWrapper, Result, SendWrapper>, > { - Action::new( + Action::new_unsync( move |registration: &SendWrapper| { let registration = registration.clone(); async move { @@ -268,7 +268,7 @@ fn create_action_create_or_update_registration() -> Action< ServiceWorkerScriptUrl, Result, SendWrapper>, > { - Action::new(move |script_url: &ServiceWorkerScriptUrl| { + Action::new_unsync(move |script_url: &ServiceWorkerScriptUrl| { let script_url = script_url.0.to_owned(); async move { if let Some(navigator) = use_window().navigator() { @@ -287,7 +287,7 @@ fn create_action_create_or_update_registration() -> Action< /// A leptos action which asynchronously fetches the current ServiceWorkerRegistration. fn create_action_get_registration( ) -> Action<(), Result, SendWrapper>> { - Action::new(move |(): &()| async move { + Action::new_unsync(move |(): &()| async move { if let Some(navigator) = use_window().navigator() { js_fut!(navigator.service_worker().get_registration()) .await diff --git a/src/use_sorted.rs b/src/use_sorted.rs index e837b4a..eea7202 100644 --- a/src/use_sorted.rs +++ b/src/use_sorted.rs @@ -78,7 +78,7 @@ pub fn use_sorted(iterable: S) -> Signal where S: Into>, T: Ord, - I: DerefMut + Clone + PartialEq + Send + Sync, + I: DerefMut + Clone + PartialEq + Send + Sync + 'static, { let iterable = iterable.into(); @@ -93,7 +93,7 @@ where pub fn use_sorted_by(iterable: S, cmp_fn: F) -> Signal where S: Into>, - I: DerefMut + Clone + PartialEq + Send + Sync, + I: DerefMut + Clone + PartialEq + Send + Sync + 'static, F: FnMut(&T, &T) -> Ordering + Clone + Send + Sync + 'static, { let iterable = iterable.into(); @@ -109,7 +109,7 @@ where pub fn use_sorted_by_key(iterable: S, key_fn: F) -> Signal where S: Into>, - I: DerefMut + Clone + PartialEq + Send + Sync, + I: DerefMut + Clone + PartialEq + Send + Sync + 'static, K: Ord, F: FnMut(&T) -> K + Clone + Send + Sync + 'static, { diff --git a/src/use_user_media.rs b/src/use_user_media.rs index aba11dc..83ec073 100644 --- a/src/use_user_media.rs +++ b/src/use_user_media.rs @@ -2,7 +2,6 @@ use crate::core::MaybeRwSignal; use cfg_if::cfg_if; use default_struct_builder::DefaultBuilder; use leptos::prelude::*; -use send_wrapper::SendWrapper; use wasm_bindgen::{JsCast, JsValue}; /// Reactive [`mediaDevices.getUserMedia`](https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/getUserMedia) streaming. @@ -60,8 +59,7 @@ pub fn use_user_media_with_options( let (enabled, set_enabled) = enabled.into_signal(); - let (stream, set_stream) = - signal(None::, SendWrapper>>); + let (stream, set_stream) = signal_local(None::>); let _start = move || async move { cfg_if! { if #[cfg(not(feature = "ssr"))] { @@ -69,10 +67,7 @@ pub fn use_user_media_with_options( return; } - let stream = create_media(video, audio) - .await - .map(SendWrapper::new) - .map_err(SendWrapper::new); + let stream = create_media(video, audio).await; set_stream.update(|s| *s = Some(stream)); } else { @@ -192,7 +187,7 @@ where /// Initially this is `None` until `start` resolved successfully. /// In case the stream couldn't be started, for example because the user didn't grant permission, /// this has the value `Some(Err(...))`. - pub stream: Signal, SendWrapper>>>, + pub stream: Signal>, LocalStorage>, /// Starts the screen streaming. Triggers the ask for permission if not already granted. pub start: StartFn, diff --git a/src/use_web_notification.rs b/src/use_web_notification.rs index afad4df..104c2fd 100644 --- a/src/use_web_notification.rs +++ b/src/use_web_notification.rs @@ -2,7 +2,6 @@ use crate::{use_supported, use_window}; use cfg_if::cfg_if; use default_struct_builder::DefaultBuilder; use leptos::prelude::{wrappers::read::Signal, *}; -use send_wrapper::SendWrapper; use std::rc::Rc; /// Reactive [Notification API](https://developer.mozilla.org/en-US/docs/Web/API/Notification). @@ -52,7 +51,7 @@ pub fn use_web_notification_with_options( ) -> UseWebNotificationReturn { let is_supported = use_supported(browser_supports_notifications); - let (notification, set_notification) = signal(None::>); + let (notification, set_notification) = signal_local(None::); let (permission, set_permission) = signal(NotificationPermission::default()); @@ -149,7 +148,7 @@ pub fn use_web_notification_with_options( notification_value.set_onerror(Some(on_error_closure.unchecked_ref())); notification_value.set_onshow(Some(on_show_closure.unchecked_ref())); - set_notification.set(Some(SendWrapper::new(notification_value))); + set_notification.set(Some(notification_value)); }); } }; @@ -462,7 +461,7 @@ where CloseFn: Fn() + Clone, { pub is_supported: Signal, - pub notification: Signal>>, + pub notification: Signal, LocalStorage>, pub show: ShowFn, pub close: CloseFn, pub permission: Signal, diff --git a/src/use_websocket.rs b/src/use_websocket.rs index 776706d..28d83b8 100644 --- a/src/use_websocket.rs +++ b/src/use_websocket.rs @@ -2,7 +2,6 @@ use cfg_if::cfg_if; use leptos::{leptos_dom::helpers::TimeoutHandle, prelude::*}; -use send_wrapper::SendWrapper; use std::sync::{atomic::AtomicBool, Arc}; use std::time::Duration; use thiserror::Error; @@ -284,7 +283,7 @@ where let (ready_state, set_ready_state) = signal(ConnectionReadyState::Closed); let (message, set_message) = signal(None); - let ws_ref: StoredValue>> = StoredValue::new(None); + let ws_ref: StoredValue, _> = StoredValue::new_local(None); let reconnect_timer_ref: StoredValue> = StoredValue::new(None); @@ -305,9 +304,7 @@ where && !reconnect_limit.is_exceeded_by(reconnect_times_ref.get_value()) && ws_ref .get_value() - .map_or(false, |ws: SendWrapper| { - ws.ready_state() != WebSocket::OPEN - }) + .map_or(false, |ws: WebSocket| ws.ready_state() != WebSocket::OPEN) { reconnect_timer_ref.set_value( set_timeout_with_handle( @@ -525,7 +522,7 @@ where onclose_closure.forget(); } - ws_ref.set_value(Some(SendWrapper::new(web_socket))); + ws_ref.set_value(Some(web_socket)); })) }); } @@ -721,7 +718,7 @@ where /// Latest message received from `WebSocket`. pub message: Signal>, /// The `WebSocket` instance. - pub ws: Option>, + pub ws: Option, /// Opens the `WebSocket` connection pub open: OpenFn, /// Closes the `WebSocket` connection