mirror of
https://github.com/adoyle0/leptos-use.git
synced 2025-01-23 17:09:21 -05:00
Merge pull request #143 from CorvusPrudens/leptos-0.7
`LocalStorage` integration
This commit is contained in:
commit
3e8fd64aa5
41 changed files with 853 additions and 605 deletions
|
@ -1,10 +1,11 @@
|
||||||
use crate::{UseDocument, UseWindow};
|
use crate::{UseDocument, UseWindow};
|
||||||
use cfg_if::cfg_if;
|
use cfg_if::cfg_if;
|
||||||
use leptos::html::HtmlElement;
|
use leptos::html::{CreateElement, ElementType};
|
||||||
use leptos::prelude::wrappers::read::Signal;
|
use leptos::prelude::wrappers::read::Signal;
|
||||||
use leptos::prelude::*;
|
use leptos::prelude::*;
|
||||||
|
use send_wrapper::SendWrapper;
|
||||||
use std::marker::PhantomData;
|
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
|
/// Used as an argument type to make it easily possible to pass either
|
||||||
///
|
///
|
||||||
|
@ -19,9 +20,9 @@ pub enum ElementMaybeSignal<T, E>
|
||||||
where
|
where
|
||||||
T: Into<E> + Clone + 'static,
|
T: Into<E> + Clone + 'static,
|
||||||
{
|
{
|
||||||
Static(Option<T>),
|
Static(SendWrapper<Option<T>>),
|
||||||
Dynamic(Signal<Option<T>>),
|
Dynamic(Signal<Option<T>, LocalStorage>),
|
||||||
_Phantom(PhantomData<E>),
|
_Phantom(PhantomData<fn() -> E>),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T, E> Default for ElementMaybeSignal<T, E>
|
impl<T, E> Default for ElementMaybeSignal<T, E>
|
||||||
|
@ -29,7 +30,7 @@ where
|
||||||
T: Into<E> + Clone + 'static,
|
T: Into<E> + Clone + 'static,
|
||||||
{
|
{
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self::Static(None)
|
Self::Static(SendWrapper::new(None))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -63,15 +64,18 @@ where
|
||||||
|
|
||||||
fn with<O>(&self, f: impl FnOnce(&Option<T>) -> O) -> O {
|
fn with<O>(&self, f: impl FnOnce(&Option<T>) -> O) -> O {
|
||||||
match self {
|
match self {
|
||||||
Self::Static(t) => f(t),
|
Self::Static(t) => f(&t),
|
||||||
Self::Dynamic(s) => s.with(f),
|
Self::Dynamic(s) => {
|
||||||
|
let value = s.get();
|
||||||
|
f(&value)
|
||||||
|
}
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn try_with<O>(&self, f: impl FnOnce(&Option<T>) -> O) -> Option<O> {
|
fn try_with<O>(&self, f: impl FnOnce(&Option<T>) -> O) -> Option<O> {
|
||||||
match self {
|
match self {
|
||||||
Self::Static(t) => Some(f(t)),
|
Self::Static(t) => Some(f(&t)),
|
||||||
Self::Dynamic(s) => s.try_with(f),
|
Self::Dynamic(s) => s.try_with(f),
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
|
@ -86,7 +90,7 @@ where
|
||||||
|
|
||||||
fn with_untracked<O>(&self, f: impl FnOnce(&Option<T>) -> O) -> O {
|
fn with_untracked<O>(&self, f: impl FnOnce(&Option<T>) -> O) -> O {
|
||||||
match self {
|
match self {
|
||||||
Self::Static(t) => f(t),
|
Self::Static(t) => f(&t),
|
||||||
Self::Dynamic(s) => s.with_untracked(f),
|
Self::Dynamic(s) => s.with_untracked(f),
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
|
@ -94,7 +98,7 @@ where
|
||||||
|
|
||||||
fn try_with_untracked<O>(&self, f: impl FnOnce(&Option<T>) -> O) -> Option<O> {
|
fn try_with_untracked<O>(&self, f: impl FnOnce(&Option<T>) -> O) -> Option<O> {
|
||||||
match self {
|
match self {
|
||||||
Self::Static(t) => Some(f(t)),
|
Self::Static(t) => Some(f(&t)),
|
||||||
Self::Dynamic(s) => s.try_with_untracked(f),
|
Self::Dynamic(s) => s.try_with_untracked(f),
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
|
@ -108,7 +112,7 @@ where
|
||||||
T: Into<E> + Clone + 'static,
|
T: Into<E> + Clone + 'static,
|
||||||
{
|
{
|
||||||
fn from(value: T) -> Self {
|
fn from(value: T) -> Self {
|
||||||
ElementMaybeSignal::Static(Some(value))
|
ElementMaybeSignal::Static(SendWrapper::new(Some(value)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -117,7 +121,7 @@ where
|
||||||
T: Into<E> + Clone + 'static,
|
T: Into<E> + Clone + 'static,
|
||||||
{
|
{
|
||||||
fn from(target: Option<T>) -> Self {
|
fn from(target: Option<T>) -> Self {
|
||||||
ElementMaybeSignal::Static(target)
|
ElementMaybeSignal::Static(SendWrapper::new(target))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -128,7 +132,7 @@ macro_rules! impl_from_deref_option {
|
||||||
E: From<$ty2> + 'static,
|
E: From<$ty2> + 'static,
|
||||||
{
|
{
|
||||||
fn from(value: $ty) -> Self {
|
fn from(value: $ty) -> Self {
|
||||||
Self::Static((*value).clone())
|
Self::Static(SendWrapper::new((*value).clone()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -146,9 +150,9 @@ where
|
||||||
fn from(target: &'a str) -> Self {
|
fn from(target: &'a str) -> Self {
|
||||||
cfg_if! { if #[cfg(feature = "ssr")] {
|
cfg_if! { if #[cfg(feature = "ssr")] {
|
||||||
let _ = target;
|
let _ = target;
|
||||||
Self::Static(None)
|
Self::Static(SendWrapper::new(None))
|
||||||
} else {
|
} else {
|
||||||
Self::Static(document().query_selector(target).unwrap_or_default())
|
Self::Static(SendWrapper::new(document().query_selector(target).unwrap_or_default()))
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -171,10 +175,10 @@ macro_rules! impl_from_signal_string {
|
||||||
fn from(signal: $ty) -> Self {
|
fn from(signal: $ty) -> Self {
|
||||||
cfg_if! { if #[cfg(feature = "ssr")] {
|
cfg_if! { if #[cfg(feature = "ssr")] {
|
||||||
let _ = signal;
|
let _ = signal;
|
||||||
Self::Dynamic(Signal::derive(|| None))
|
Self::Dynamic(Signal::derive_local(|| None))
|
||||||
} else {
|
} else {
|
||||||
Self::Dynamic(
|
Self::Dynamic(
|
||||||
Signal::derive(move || document().query_selector(&signal.get()).unwrap_or_default()),
|
Signal::derive_local(move || document().query_selector(&signal.get()).unwrap_or_default()),
|
||||||
)
|
)
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
@ -187,10 +191,10 @@ impl_from_signal_string!(ReadSignal<String>);
|
||||||
impl_from_signal_string!(RwSignal<String>);
|
impl_from_signal_string!(RwSignal<String>);
|
||||||
impl_from_signal_string!(Memo<String>);
|
impl_from_signal_string!(Memo<String>);
|
||||||
|
|
||||||
impl_from_signal_string!(Signal<&str>);
|
impl_from_signal_string!(Signal<&'static str>);
|
||||||
impl_from_signal_string!(ReadSignal<&str>);
|
impl_from_signal_string!(ReadSignal<&'static str>);
|
||||||
impl_from_signal_string!(RwSignal<&str>);
|
impl_from_signal_string!(RwSignal<&'static str>);
|
||||||
impl_from_signal_string!(Memo<&str>);
|
impl_from_signal_string!(Memo<&'static str>);
|
||||||
|
|
||||||
// From signal ///////////////////////////////////////////////////////////////
|
// From signal ///////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
@ -207,10 +211,10 @@ macro_rules! impl_from_signal_option {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
impl_from_signal_option!(Signal<Option<T>>);
|
impl_from_signal_option!(Signal<Option<T>, LocalStorage>);
|
||||||
impl_from_signal_option!(ReadSignal<Option<T>>);
|
impl_from_signal_option!(ReadSignal<Option<T>, LocalStorage>);
|
||||||
impl_from_signal_option!(RwSignal<Option<T>>);
|
impl_from_signal_option!(RwSignal<Option<T>, LocalStorage>);
|
||||||
impl_from_signal_option!(Memo<Option<T>>);
|
impl_from_signal_option!(Memo<Option<T>, LocalStorage>);
|
||||||
|
|
||||||
macro_rules! impl_from_signal {
|
macro_rules! impl_from_signal {
|
||||||
($ty:ty) => {
|
($ty:ty) => {
|
||||||
|
@ -219,16 +223,16 @@ macro_rules! impl_from_signal {
|
||||||
T: Into<E> + Clone + 'static,
|
T: Into<E> + Clone + 'static,
|
||||||
{
|
{
|
||||||
fn from(signal: $ty) -> Self {
|
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<T>);
|
impl_from_signal!(Signal<T, LocalStorage>);
|
||||||
impl_from_signal!(ReadSignal<T>);
|
impl_from_signal!(ReadSignal<T, LocalStorage>);
|
||||||
impl_from_signal!(RwSignal<T>);
|
impl_from_signal!(RwSignal<T, LocalStorage>);
|
||||||
impl_from_signal!(Memo<T>);
|
impl_from_signal!(Memo<T, LocalStorage>);
|
||||||
|
|
||||||
// From NodeRef //////////////////////////////////////////////////////////////
|
// From NodeRef //////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
@ -236,13 +240,13 @@ macro_rules! impl_from_node_ref {
|
||||||
($ty:ty) => {
|
($ty:ty) => {
|
||||||
impl<R> From<NodeRef<R>> for ElementMaybeSignal<$ty, $ty>
|
impl<R> From<NodeRef<R>> for ElementMaybeSignal<$ty, $ty>
|
||||||
where
|
where
|
||||||
R: ElementDescriptor + Clone + 'static,
|
R: ElementType + CreateElement<Dom> + Clone + Send + Sync + 'static,
|
||||||
|
R::Output: JsCast + Into<$ty> + Clone + 'static,
|
||||||
{
|
{
|
||||||
fn from(node_ref: NodeRef<R>) -> Self {
|
fn from(node_ref: NodeRef<R>) -> Self {
|
||||||
Self::Dynamic(Signal::derive(move || {
|
Self::Dynamic(Signal::derive_local(move || {
|
||||||
node_ref.get().map(move |el| {
|
node_ref.get().map(move |el| {
|
||||||
let el = el.into_any();
|
let el: $ty = el.clone().into();
|
||||||
let el: $ty = el.deref().clone().into();
|
|
||||||
el
|
el
|
||||||
})
|
})
|
||||||
}))
|
}))
|
||||||
|
@ -255,90 +259,90 @@ impl_from_node_ref!(web_sys::EventTarget);
|
||||||
impl_from_node_ref!(web_sys::Element);
|
impl_from_node_ref!(web_sys::Element);
|
||||||
impl_from_node_ref!(web_sys::HtmlElement);
|
impl_from_node_ref!(web_sys::HtmlElement);
|
||||||
|
|
||||||
// From leptos::html::HTMLElement ///////////////////////////////////////////////
|
// // From leptos::html::HTMLElement ///////////////////////////////////////////////
|
||||||
|
//
|
||||||
macro_rules! impl_from_html_element {
|
// macro_rules! impl_from_html_element {
|
||||||
($ty:ty) => {
|
// ($ty:ty) => {
|
||||||
impl<HtmlEl> From<HtmlElement<HtmlEl>> for ElementMaybeSignal<$ty, $ty>
|
// impl<HtmlEl> From<HtmlElement<HtmlEl>> for ElementMaybeSignal<$ty, $ty>
|
||||||
where
|
// where
|
||||||
HtmlEl: ElementDescriptor + std::ops::Deref<Target = $ty>,
|
// HtmlEl: ElementDescriptor + std::ops::Deref<Target = $ty>,
|
||||||
{
|
// {
|
||||||
fn from(value: HtmlElement<HtmlEl>) -> Self {
|
// fn from(value: HtmlElement<HtmlEl>) -> Self {
|
||||||
let el: &$ty = value.deref();
|
// let el: &$ty = value.deref();
|
||||||
Self::Static(Some(el.clone()))
|
// Self::Static(Some(el.clone()))
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
};
|
// };
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
impl_from_html_element!(web_sys::EventTarget);
|
// impl_from_html_element!(web_sys::EventTarget);
|
||||||
impl_from_html_element!(web_sys::Element);
|
// impl_from_html_element!(web_sys::Element);
|
||||||
impl_from_html_element!(web_sys::HtmlElement);
|
// impl_from_html_element!(web_sys::HtmlElement);
|
||||||
|
//
|
||||||
// From Signal<leptos::html::HTMLElement> /////////////////////////////////////////
|
// // From Signal<leptos::html::HTMLElement> /////////////////////////////////////////
|
||||||
|
//
|
||||||
macro_rules! impl_from_signal_html_element {
|
// macro_rules! impl_from_signal_html_element {
|
||||||
($signal:ty, $ty:ty) => {
|
// ($signal:ty, $ty:ty) => {
|
||||||
impl<HtmlEl> From<$signal> for ElementMaybeSignal<$ty, $ty>
|
// impl<HtmlEl> From<$signal> for ElementMaybeSignal<$ty, $ty>
|
||||||
where
|
// where
|
||||||
HtmlEl: ElementDescriptor + std::ops::Deref<Target = $ty> + Clone,
|
// HtmlEl: ElementDescriptor + std::ops::Deref<Target = $ty> + Clone,
|
||||||
{
|
// {
|
||||||
fn from(value: $signal) -> Self {
|
// fn from(value: $signal) -> Self {
|
||||||
Self::Dynamic(Signal::derive(move || {
|
// Self::Dynamic(Signal::derive(move || {
|
||||||
let value = value.get();
|
// let value = value.get();
|
||||||
let el: &$ty = value.deref();
|
// let el: &$ty = value.deref();
|
||||||
Some(el.clone())
|
// Some(el.clone())
|
||||||
}))
|
// }))
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
};
|
// };
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
impl_from_signal_html_element!(Signal<HtmlElement<HtmlEl>>, web_sys::EventTarget);
|
// 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!(ReadSignal<HtmlElement<HtmlEl>>, web_sys::EventTarget);
|
||||||
impl_from_signal_html_element!(RwSignal<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!(Memo<HtmlElement<HtmlEl>>, web_sys::EventTarget);
|
||||||
|
//
|
||||||
impl_from_signal_html_element!(Signal<HtmlElement<HtmlEl>>, web_sys::Element);
|
// 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!(ReadSignal<HtmlElement<HtmlEl>>, web_sys::Element);
|
||||||
impl_from_signal_html_element!(RwSignal<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);
|
// impl_from_signal_html_element!(Memo<HtmlElement<HtmlEl>>, web_sys::Element);
|
||||||
|
//
|
||||||
// From Signal<Option<leptos::html::HTMLElement>> /////////////////////////////////////////
|
// // From Signal<Option<leptos::html::HTMLElement>> /////////////////////////////////////////
|
||||||
|
//
|
||||||
macro_rules! impl_from_signal_html_element {
|
// macro_rules! impl_from_signal_html_element {
|
||||||
($signal:ty, $ty:ty) => {
|
// ($signal:ty, $ty:ty) => {
|
||||||
impl<HtmlEl> From<$signal> for ElementMaybeSignal<$ty, $ty>
|
// impl<HtmlEl> From<$signal> for ElementMaybeSignal<$ty, $ty>
|
||||||
where
|
// where
|
||||||
HtmlEl: ElementDescriptor + std::ops::Deref<Target = $ty> + Clone,
|
// HtmlEl: ElementDescriptor + std::ops::Deref<Target = $ty> + Clone,
|
||||||
{
|
// {
|
||||||
fn from(value: $signal) -> Self {
|
// fn from(value: $signal) -> Self {
|
||||||
Self::Dynamic(Signal::derive(move || {
|
// Self::Dynamic(Signal::derive(move || {
|
||||||
let el: Option<$ty> = value.get().map(|el| el.deref().clone());
|
// let el: Option<$ty> = value.get().map(|el| el.deref().clone());
|
||||||
el
|
// el
|
||||||
}))
|
// }))
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
};
|
// };
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
impl_from_signal_html_element!(Signal<Option<HtmlElement<HtmlEl>>>, web_sys::EventTarget);
|
// impl_from_signal_html_element!(Signal<Option<HtmlElement<HtmlEl>>>, web_sys::EventTarget);
|
||||||
impl_from_signal_html_element!(
|
// impl_from_signal_html_element!(
|
||||||
ReadSignal<Option<HtmlElement<HtmlEl>>>,
|
// ReadSignal<Option<HtmlElement<HtmlEl>>>,
|
||||||
web_sys::EventTarget
|
// web_sys::EventTarget
|
||||||
);
|
// );
|
||||||
impl_from_signal_html_element!(RwSignal<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!(Memo<Option<HtmlElement<HtmlEl>>>, web_sys::EventTarget);
|
||||||
|
//
|
||||||
impl_from_signal_html_element!(Signal<Option<HtmlElement<HtmlEl>>>, web_sys::Element);
|
// 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!(ReadSignal<Option<HtmlElement<HtmlEl>>>, web_sys::Element);
|
||||||
impl_from_signal_html_element!(RwSignal<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!(Memo<Option<HtmlElement<HtmlEl>>>, web_sys::Element);
|
||||||
|
//
|
||||||
impl_from_signal_html_element!(Signal<Option<HtmlElement<HtmlEl>>>, web_sys::HtmlElement);
|
// impl_from_signal_html_element!(Signal<Option<HtmlElement<HtmlEl>>>, web_sys::HtmlElement);
|
||||||
impl_from_signal_html_element!(
|
// impl_from_signal_html_element!(
|
||||||
ReadSignal<Option<HtmlElement<HtmlEl>>>,
|
// ReadSignal<Option<HtmlElement<HtmlEl>>>,
|
||||||
web_sys::HtmlElement
|
// web_sys::HtmlElement
|
||||||
);
|
// );
|
||||||
impl_from_signal_html_element!(RwSignal<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);
|
// impl_from_signal_html_element!(Memo<Option<HtmlElement<HtmlEl>>>, web_sys::HtmlElement);
|
||||||
|
|
|
@ -1,11 +1,12 @@
|
||||||
use crate::core::ElementMaybeSignal;
|
use crate::core::ElementMaybeSignal;
|
||||||
use crate::{UseDocument, UseWindow};
|
use crate::{UseDocument, UseWindow};
|
||||||
use cfg_if::cfg_if;
|
use cfg_if::cfg_if;
|
||||||
use leptos::html::ElementDescriptor;
|
use leptos::html::ElementType;
|
||||||
use leptos::prelude::wrappers::read::Signal;
|
use leptos::prelude::wrappers::read::Signal;
|
||||||
use leptos::prelude::*;
|
use leptos::prelude::*;
|
||||||
|
use send_wrapper::SendWrapper;
|
||||||
use std::marker::PhantomData;
|
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
|
/// Used as an argument type to make it easily possible to pass either
|
||||||
///
|
///
|
||||||
|
@ -20,9 +21,9 @@ pub enum ElementsMaybeSignal<T, E>
|
||||||
where
|
where
|
||||||
T: Into<E> + Clone + 'static,
|
T: Into<E> + Clone + 'static,
|
||||||
{
|
{
|
||||||
Static(Vec<Option<T>>),
|
Static(SendWrapper<Vec<Option<T>>>),
|
||||||
Dynamic(Signal<Vec<Option<T>>>),
|
Dynamic(Signal<Vec<Option<T>>, LocalStorage>),
|
||||||
_Phantom(PhantomData<E>),
|
_Phantom(PhantomData<fn() -> E>),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T, E> Default for ElementsMaybeSignal<T, E>
|
impl<T, E> Default for ElementsMaybeSignal<T, E>
|
||||||
|
@ -30,7 +31,7 @@ where
|
||||||
T: Into<E> + Clone + 'static,
|
T: Into<E> + Clone + 'static,
|
||||||
{
|
{
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self::Static(vec![])
|
Self::Static(SendWrapper::new(vec![]))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -109,7 +110,7 @@ where
|
||||||
T: Into<E> + Clone + 'static,
|
T: Into<E> + Clone + 'static,
|
||||||
{
|
{
|
||||||
fn from(value: T) -> Self {
|
fn from(value: T) -> Self {
|
||||||
ElementsMaybeSignal::Static(vec![Some(value)])
|
ElementsMaybeSignal::Static(SendWrapper::new(vec![Some(value)]))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -118,7 +119,7 @@ where
|
||||||
T: Into<E> + Clone + 'static,
|
T: Into<E> + Clone + 'static,
|
||||||
{
|
{
|
||||||
fn from(target: Option<T>) -> Self {
|
fn from(target: Option<T>) -> Self {
|
||||||
ElementsMaybeSignal::Static(vec![target])
|
ElementsMaybeSignal::Static(SendWrapper::new(vec![target]))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -129,7 +130,7 @@ macro_rules! impl_from_deref_option {
|
||||||
E: From<$ty2> + 'static,
|
E: From<$ty2> + 'static,
|
||||||
{
|
{
|
||||||
fn from(value: $ty) -> Self {
|
fn from(value: $ty) -> Self {
|
||||||
Self::Static(vec![(*value).clone()])
|
Self::Static(SendWrapper::new(vec![(*value).clone()]))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -147,7 +148,7 @@ where
|
||||||
fn from(target: &'a str) -> Self {
|
fn from(target: &'a str) -> Self {
|
||||||
cfg_if! { if #[cfg(feature = "ssr")] {
|
cfg_if! { if #[cfg(feature = "ssr")] {
|
||||||
let _ = target;
|
let _ = target;
|
||||||
Self::Static(vec![])
|
Self::Static(SendWrapper::new(vec![]))
|
||||||
} else {
|
} else {
|
||||||
if let Ok(node_list) = document().query_selector_all(target) {
|
if let Ok(node_list) = document().query_selector_all(target) {
|
||||||
let mut list = Vec::with_capacity(node_list.length() as usize);
|
let mut list = Vec::with_capacity(node_list.length() as usize);
|
||||||
|
@ -156,9 +157,9 @@ where
|
||||||
list.push(Some(node));
|
list.push(Some(node));
|
||||||
}
|
}
|
||||||
|
|
||||||
Self::Static(list)
|
Self::Static(SendWrapper::new(list))
|
||||||
} else {
|
} else {
|
||||||
Self::Static(vec![])
|
Self::Static(SendWrapper::new(vec![]))
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
@ -182,7 +183,7 @@ macro_rules! impl_from_signal_string {
|
||||||
fn from(signal: $ty) -> Self {
|
fn from(signal: $ty) -> Self {
|
||||||
cfg_if! { if #[cfg(feature = "ssr")] {
|
cfg_if! { if #[cfg(feature = "ssr")] {
|
||||||
Self::Dynamic(
|
Self::Dynamic(
|
||||||
Signal::derive(move || {
|
Signal::derive_local(move || {
|
||||||
if let Ok(node_list) = document().query_selector_all(&signal.get()) {
|
if let Ok(node_list) = document().query_selector_all(&signal.get()) {
|
||||||
let mut list = Vec::with_capacity(node_list.length() as usize);
|
let mut list = Vec::with_capacity(node_list.length() as usize);
|
||||||
for i in 0..node_list.length() {
|
for i in 0..node_list.length() {
|
||||||
|
@ -197,7 +198,7 @@ macro_rules! impl_from_signal_string {
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
let _ = signal;
|
let _ = signal;
|
||||||
Self::Dynamic(Signal::derive(Vec::new))
|
Self::Dynamic(Signal::derive_local(Vec::new))
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -209,10 +210,10 @@ impl_from_signal_string!(ReadSignal<String>);
|
||||||
impl_from_signal_string!(RwSignal<String>);
|
impl_from_signal_string!(RwSignal<String>);
|
||||||
impl_from_signal_string!(Memo<String>);
|
impl_from_signal_string!(Memo<String>);
|
||||||
|
|
||||||
impl_from_signal_string!(Signal<&str>);
|
impl_from_signal_string!(Signal<&'static str>);
|
||||||
impl_from_signal_string!(ReadSignal<&str>);
|
impl_from_signal_string!(ReadSignal<&'static str>);
|
||||||
impl_from_signal_string!(RwSignal<&str>);
|
impl_from_signal_string!(RwSignal<&'static str>);
|
||||||
impl_from_signal_string!(Memo<&str>);
|
impl_from_signal_string!(Memo<&'static str>);
|
||||||
|
|
||||||
// From single signal ///////////////////////////////////////////////////////////////
|
// From single signal ///////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
@ -223,16 +224,16 @@ macro_rules! impl_from_signal_option {
|
||||||
T: Into<E> + Clone + 'static,
|
T: Into<E> + Clone + 'static,
|
||||||
{
|
{
|
||||||
fn from(signal: $ty) -> Self {
|
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<Option<T>>);
|
impl_from_signal_option!(Signal<Option<T>, LocalStorage>);
|
||||||
impl_from_signal_option!(ReadSignal<Option<T>>);
|
impl_from_signal_option!(ReadSignal<Option<T>, LocalStorage>);
|
||||||
impl_from_signal_option!(RwSignal<Option<T>>);
|
impl_from_signal_option!(RwSignal<Option<T>, LocalStorage>);
|
||||||
impl_from_signal_option!(Memo<Option<T>>);
|
impl_from_signal_option!(Memo<Option<T>, LocalStorage>);
|
||||||
|
|
||||||
macro_rules! impl_from_signal {
|
macro_rules! impl_from_signal {
|
||||||
($ty:ty) => {
|
($ty:ty) => {
|
||||||
|
@ -241,16 +242,16 @@ macro_rules! impl_from_signal {
|
||||||
T: Into<E> + Clone + 'static,
|
T: Into<E> + Clone + 'static,
|
||||||
{
|
{
|
||||||
fn from(signal: $ty) -> Self {
|
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<T>);
|
impl_from_signal!(Signal<T, LocalStorage>);
|
||||||
impl_from_signal!(ReadSignal<T>);
|
impl_from_signal!(ReadSignal<T, LocalStorage>);
|
||||||
impl_from_signal!(RwSignal<T>);
|
impl_from_signal!(RwSignal<T, LocalStorage>);
|
||||||
impl_from_signal!(Memo<T>);
|
impl_from_signal!(Memo<T, LocalStorage>);
|
||||||
|
|
||||||
// From single NodeRef //////////////////////////////////////////////////////////////
|
// From single NodeRef //////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
@ -258,13 +259,13 @@ macro_rules! impl_from_node_ref {
|
||||||
($ty:ty) => {
|
($ty:ty) => {
|
||||||
impl<R> From<NodeRef<R>> for ElementsMaybeSignal<$ty, $ty>
|
impl<R> From<NodeRef<R>> for ElementsMaybeSignal<$ty, $ty>
|
||||||
where
|
where
|
||||||
R: ElementDescriptor + Clone + 'static,
|
R: ElementType + Clone + 'static,
|
||||||
|
R::Output: JsCast + Into<$ty> + Clone + 'static,
|
||||||
{
|
{
|
||||||
fn from(node_ref: NodeRef<R>) -> Self {
|
fn from(node_ref: NodeRef<R>) -> Self {
|
||||||
Self::Dynamic(Signal::derive(move || {
|
Self::Dynamic(Signal::derive_local(move || {
|
||||||
vec![node_ref.get().map(move |el| {
|
vec![node_ref.get().map(move |el| {
|
||||||
let el = el.into_any();
|
let el: $ty = el.clone().into();
|
||||||
let el: $ty = el.deref().clone().into();
|
|
||||||
el
|
el
|
||||||
})]
|
})]
|
||||||
}))
|
}))
|
||||||
|
@ -278,22 +279,23 @@ impl_from_node_ref!(web_sys::Element);
|
||||||
|
|
||||||
// From single leptos::html::HTMLElement ///////////////////////////////////////////
|
// From single leptos::html::HTMLElement ///////////////////////////////////////////
|
||||||
|
|
||||||
macro_rules! impl_from_html_element {
|
// macro_rules! impl_from_html_element {
|
||||||
($ty:ty) => {
|
// ($ty:ty) => {
|
||||||
impl<HtmlEl> From<HtmlElement<HtmlEl>> for ElementsMaybeSignal<$ty, $ty>
|
// impl<E, At, Ch, Rndr> From<HtmlElement<E, At, Ch, Rndr>> for ElementsMaybeSignal<$ty, $ty>
|
||||||
where
|
// where
|
||||||
HtmlEl: ElementDescriptor + std::ops::Deref<Target = $ty>,
|
// E: ElementType,
|
||||||
{
|
// E::Output: std::ops::Deref<Target = $ty>,
|
||||||
fn from(value: HtmlElement<HtmlEl>) -> Self {
|
// {
|
||||||
let el: &$ty = value.deref();
|
// fn from(value: HtmlElement<E, At, Ch, Rndr>) -> Self {
|
||||||
Self::Static(vec![Some(el.clone())])
|
// let el: &$ty = value.deref();
|
||||||
}
|
// Self::Static(vec![Some(el.clone())])
|
||||||
}
|
// }
|
||||||
};
|
// }
|
||||||
}
|
// };
|
||||||
|
// }
|
||||||
impl_from_html_element!(web_sys::EventTarget);
|
//
|
||||||
impl_from_html_element!(web_sys::Element);
|
// impl_from_html_element!(web_sys::EventTarget);
|
||||||
|
// impl_from_html_element!(web_sys::Element);
|
||||||
|
|
||||||
// From multiple static elements //////////////////////////////////////////////////////
|
// From multiple static elements //////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
@ -302,7 +304,9 @@ where
|
||||||
T: Into<E> + Clone + 'static,
|
T: Into<E> + Clone + 'static,
|
||||||
{
|
{
|
||||||
fn from(target: &[T]) -> Self {
|
fn from(target: &[T]) -> Self {
|
||||||
Self::Static(target.iter().map(|t| Some(t.clone())).collect())
|
Self::Static(SendWrapper::new(
|
||||||
|
target.iter().map(|t| Some(t.clone())).collect(),
|
||||||
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -311,7 +315,7 @@ where
|
||||||
T: Into<E> + Clone + 'static,
|
T: Into<E> + Clone + 'static,
|
||||||
{
|
{
|
||||||
fn from(target: &[Option<T>]) -> Self {
|
fn from(target: &[Option<T>]) -> Self {
|
||||||
Self::Static(target.to_vec())
|
Self::Static(SendWrapper::new(target.iter().map(|t| t.clone()).collect()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -320,7 +324,9 @@ where
|
||||||
T: Into<E> + Clone + 'static,
|
T: Into<E> + Clone + 'static,
|
||||||
{
|
{
|
||||||
fn from(target: Vec<T>) -> Self {
|
fn from(target: Vec<T>) -> Self {
|
||||||
Self::Static(target.iter().map(|t| Some(t.clone())).collect())
|
Self::Static(SendWrapper::new(
|
||||||
|
target.iter().map(|t| Some(t.clone())).collect(),
|
||||||
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -329,7 +335,7 @@ where
|
||||||
T: Into<E> + Clone + 'static,
|
T: Into<E> + Clone + 'static,
|
||||||
{
|
{
|
||||||
fn from(target: Vec<Option<T>>) -> Self {
|
fn from(target: Vec<Option<T>>) -> Self {
|
||||||
Self::Static(target.to_vec())
|
Self::Static(SendWrapper::new(target.into_iter().map(|t| t).collect()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -338,7 +344,9 @@ where
|
||||||
T: Into<E> + Clone + 'static,
|
T: Into<E> + Clone + 'static,
|
||||||
{
|
{
|
||||||
fn from(target: [T; C]) -> Self {
|
fn from(target: [T; C]) -> Self {
|
||||||
Self::Static(target.iter().map(|t| Some(t.clone())).collect())
|
Self::Static(SendWrapper::new(
|
||||||
|
target.into_iter().map(|t| Some(t)).collect(),
|
||||||
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -347,7 +355,7 @@ where
|
||||||
T: Into<E> + Clone + 'static,
|
T: Into<E> + Clone + 'static,
|
||||||
{
|
{
|
||||||
fn from(target: [Option<T>; C]) -> Self {
|
fn from(target: [Option<T>; C]) -> Self {
|
||||||
Self::Static(target.to_vec())
|
Self::Static(SendWrapper::new(target.into_iter().collect()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -356,30 +364,32 @@ where
|
||||||
macro_rules! impl_from_strings_inner {
|
macro_rules! impl_from_strings_inner {
|
||||||
($el_ty:ty, $str_ty:ty, $target:ident) => {
|
($el_ty:ty, $str_ty:ty, $target:ident) => {
|
||||||
Self::Static(
|
Self::Static(
|
||||||
$target
|
SendWrapper::new(
|
||||||
.iter()
|
$target
|
||||||
.filter_map(|sel: &$str_ty| -> Option<Vec<Option<$el_ty>>> {
|
.iter()
|
||||||
cfg_if! { if #[cfg(feature = "ssr")] {
|
.filter_map(|sel: &$str_ty| -> Option<Vec<Option<$el_ty>>> {
|
||||||
let _ = sel;
|
cfg_if! { if #[cfg(feature = "ssr")] {
|
||||||
None
|
let _ = sel;
|
||||||
} 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
|
None
|
||||||
}
|
} else {
|
||||||
}}
|
use wasm_bindgen::JsCast;
|
||||||
})
|
|
||||||
.flatten()
|
if let Ok(node_list) = document().query_selector_all(sel) {
|
||||||
.collect(),
|
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(),
|
||||||
|
)
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -418,101 +428,101 @@ impl_from_strings!(web_sys::EventTarget, String);
|
||||||
|
|
||||||
// From signal of vec ////////////////////////////////////////////////////////////////
|
// From signal of vec ////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
impl<T, E> From<Signal<Vec<T>>> for ElementsMaybeSignal<T, E>
|
impl<T, E> From<Signal<Vec<T>, LocalStorage>> for ElementsMaybeSignal<T, E>
|
||||||
where
|
where
|
||||||
T: Into<E> + Clone + 'static,
|
T: Into<E> + Clone + 'static,
|
||||||
{
|
{
|
||||||
fn from(signal: Signal<Vec<T>>) -> Self {
|
fn from(signal: Signal<Vec<T>, LocalStorage>) -> Self {
|
||||||
Self::Dynamic(Signal::derive(move || {
|
Self::Dynamic(Signal::derive_local(move || {
|
||||||
signal.get().into_iter().map(|t| Some(t)).collect()
|
signal.get().into_iter().map(|t| Some(t)).collect()
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T, E> From<Signal<Vec<Option<T>>>> for ElementsMaybeSignal<T, E>
|
impl<T, E> From<Signal<Vec<Option<T>>, LocalStorage>> for ElementsMaybeSignal<T, E>
|
||||||
where
|
where
|
||||||
T: Into<E> + Clone + 'static,
|
T: Into<E> + Clone + 'static,
|
||||||
{
|
{
|
||||||
fn from(target: Signal<Vec<Option<T>>>) -> Self {
|
fn from(target: Signal<Vec<Option<T>>, LocalStorage>) -> Self {
|
||||||
Self::Dynamic(target)
|
Self::Dynamic(target)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// From multiple signals //////////////////////////////////////////////////////////////
|
// From multiple signals //////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
impl<T, E> From<&[Signal<T>]> for ElementsMaybeSignal<T, E>
|
impl<T, E> From<&[Signal<T, LocalStorage>]> for ElementsMaybeSignal<T, E>
|
||||||
where
|
where
|
||||||
T: Into<E> + Clone + 'static,
|
T: Into<E> + Clone + 'static,
|
||||||
{
|
{
|
||||||
fn from(list: &[Signal<T>]) -> Self {
|
fn from(list: &[Signal<T, LocalStorage>]) -> Self {
|
||||||
let list = list.to_vec();
|
let list = list.to_vec();
|
||||||
|
|
||||||
Self::Dynamic(Signal::derive(move || {
|
Self::Dynamic(Signal::derive_local(move || {
|
||||||
list.iter().map(|t| Some(t.get())).collect()
|
list.iter().map(|t| Some(t.get())).collect()
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T, E> From<&[Signal<Option<T>>]> for ElementsMaybeSignal<T, E>
|
impl<T, E> From<&[Signal<Option<T>, LocalStorage>]> for ElementsMaybeSignal<T, E>
|
||||||
where
|
where
|
||||||
T: Into<E> + Clone + 'static,
|
T: Into<E> + Clone + 'static,
|
||||||
{
|
{
|
||||||
fn from(list: &[Signal<Option<T>>]) -> Self {
|
fn from(list: &[Signal<Option<T>, LocalStorage>]) -> Self {
|
||||||
let list = list.to_vec();
|
let list = list.to_vec();
|
||||||
|
|
||||||
Self::Dynamic(Signal::derive(move || {
|
Self::Dynamic(Signal::derive_local(move || {
|
||||||
list.iter().map(|t| t.get()).collect()
|
list.iter().map(|t| t.get()).collect()
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T, E> From<Vec<Signal<T>>> for ElementsMaybeSignal<T, E>
|
impl<T, E> From<Vec<Signal<T, LocalStorage>>> for ElementsMaybeSignal<T, E>
|
||||||
where
|
where
|
||||||
T: Into<E> + Clone + 'static,
|
T: Into<E> + Clone + 'static,
|
||||||
{
|
{
|
||||||
fn from(list: Vec<Signal<T>>) -> Self {
|
fn from(list: Vec<Signal<T, LocalStorage>>) -> Self {
|
||||||
let list = list.clone();
|
let list = list.clone();
|
||||||
|
|
||||||
Self::Dynamic(Signal::derive(move || {
|
Self::Dynamic(Signal::derive_local(move || {
|
||||||
list.iter().map(|t| Some(t.get())).collect()
|
list.iter().map(|t| Some(t.get())).collect()
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T, E> From<Vec<Signal<Option<T>>>> for ElementsMaybeSignal<T, E>
|
impl<T, E> From<Vec<Signal<Option<T>, LocalStorage>>> for ElementsMaybeSignal<T, E>
|
||||||
where
|
where
|
||||||
T: Into<E> + Clone + 'static,
|
T: Into<E> + Clone + 'static,
|
||||||
{
|
{
|
||||||
fn from(list: Vec<Signal<Option<T>>>) -> Self {
|
fn from(list: Vec<Signal<Option<T>, LocalStorage>>) -> Self {
|
||||||
let list = list.clone();
|
let list = list.clone();
|
||||||
|
|
||||||
Self::Dynamic(Signal::derive(move || {
|
Self::Dynamic(Signal::derive_local(move || {
|
||||||
list.iter().map(|t| t.get()).collect()
|
list.iter().map(|t| t.get()).collect()
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T, E, const C: usize> From<[Signal<T>; C]> for ElementsMaybeSignal<T, E>
|
impl<T, E, const C: usize> From<[Signal<T, LocalStorage>; C]> for ElementsMaybeSignal<T, E>
|
||||||
where
|
where
|
||||||
T: Into<E> + Clone + 'static,
|
T: Into<E> + Clone + 'static,
|
||||||
{
|
{
|
||||||
fn from(list: [Signal<T>; C]) -> Self {
|
fn from(list: [Signal<T, LocalStorage>; C]) -> Self {
|
||||||
let list = list.to_vec();
|
let list = list.to_vec();
|
||||||
|
|
||||||
Self::Dynamic(Signal::derive(move || {
|
Self::Dynamic(Signal::derive_local(move || {
|
||||||
list.iter().map(|t| Some(t.get())).collect()
|
list.iter().map(|t| Some(t.get())).collect()
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T, E, const C: usize> From<[Signal<Option<T>>; C]> for ElementsMaybeSignal<T, E>
|
impl<T, E, const C: usize> From<[Signal<Option<T>, LocalStorage>; C]> for ElementsMaybeSignal<T, E>
|
||||||
where
|
where
|
||||||
T: Into<E> + Clone + 'static,
|
T: Into<E> + Clone + 'static,
|
||||||
{
|
{
|
||||||
fn from(list: [Signal<Option<T>>; C]) -> Self {
|
fn from(list: [Signal<Option<T>, LocalStorage>; C]) -> Self {
|
||||||
let list = list.to_vec();
|
let list = list.to_vec();
|
||||||
|
|
||||||
Self::Dynamic(Signal::derive(move || {
|
Self::Dynamic(Signal::derive_local(move || {
|
||||||
list.iter().map(|t| t.get()).collect()
|
list.iter().map(|t| t.get()).collect()
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
@ -522,13 +532,12 @@ where
|
||||||
|
|
||||||
macro_rules! impl_from_multi_node_ref_inner {
|
macro_rules! impl_from_multi_node_ref_inner {
|
||||||
($ty:ty, $node_refs:ident) => {
|
($ty:ty, $node_refs:ident) => {
|
||||||
Self::Dynamic(Signal::derive(move || {
|
Self::Dynamic(Signal::derive_local(move || {
|
||||||
$node_refs
|
$node_refs
|
||||||
.iter()
|
.iter()
|
||||||
.map(|node_ref| {
|
.map(|node_ref| {
|
||||||
node_ref.get().map(move |el| {
|
node_ref.get().map(move |el| {
|
||||||
let el = el.into_any();
|
let el: $ty = el.clone().into();
|
||||||
let el: $ty = el.deref().clone().into();
|
|
||||||
el
|
el
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
@ -541,7 +550,8 @@ macro_rules! impl_from_multi_node_ref {
|
||||||
($ty:ty) => {
|
($ty:ty) => {
|
||||||
impl<R> From<&[NodeRef<R>]> for ElementsMaybeSignal<$ty, $ty>
|
impl<R> From<&[NodeRef<R>]> for ElementsMaybeSignal<$ty, $ty>
|
||||||
where
|
where
|
||||||
R: ElementDescriptor + Clone + 'static,
|
R: ElementType + Clone + 'static,
|
||||||
|
R::Output: JsCast + Into<$ty> + Clone + 'static,
|
||||||
{
|
{
|
||||||
fn from(node_refs: &[NodeRef<R>]) -> Self {
|
fn from(node_refs: &[NodeRef<R>]) -> Self {
|
||||||
let node_refs = node_refs.to_vec();
|
let node_refs = node_refs.to_vec();
|
||||||
|
@ -551,7 +561,8 @@ macro_rules! impl_from_multi_node_ref {
|
||||||
|
|
||||||
impl<R, const C: usize> From<[NodeRef<R>; C]> for ElementsMaybeSignal<$ty, $ty>
|
impl<R, const C: usize> From<[NodeRef<R>; C]> for ElementsMaybeSignal<$ty, $ty>
|
||||||
where
|
where
|
||||||
R: ElementDescriptor + Clone + 'static,
|
R: ElementType + Clone + 'static,
|
||||||
|
R::Output: JsCast + Into<$ty> + Clone + 'static,
|
||||||
{
|
{
|
||||||
fn from(node_refs: [NodeRef<R>; C]) -> Self {
|
fn from(node_refs: [NodeRef<R>; C]) -> Self {
|
||||||
let node_refs = node_refs.to_vec();
|
let node_refs = node_refs.to_vec();
|
||||||
|
@ -561,7 +572,8 @@ macro_rules! impl_from_multi_node_ref {
|
||||||
|
|
||||||
impl<R> From<Vec<NodeRef<R>>> for ElementsMaybeSignal<$ty, $ty>
|
impl<R> From<Vec<NodeRef<R>>> for ElementsMaybeSignal<$ty, $ty>
|
||||||
where
|
where
|
||||||
R: ElementDescriptor + Clone + 'static,
|
R: ElementType + Clone + 'static,
|
||||||
|
R::Output: JsCast + Into<$ty> + Clone + 'static,
|
||||||
{
|
{
|
||||||
fn from(node_refs: Vec<NodeRef<R>>) -> Self {
|
fn from(node_refs: Vec<NodeRef<R>>) -> Self {
|
||||||
let node_refs = node_refs.clone();
|
let node_refs = node_refs.clone();
|
||||||
|
@ -574,66 +586,71 @@ macro_rules! impl_from_multi_node_ref {
|
||||||
impl_from_multi_node_ref!(web_sys::EventTarget);
|
impl_from_multi_node_ref!(web_sys::EventTarget);
|
||||||
impl_from_multi_node_ref!(web_sys::Element);
|
impl_from_multi_node_ref!(web_sys::Element);
|
||||||
|
|
||||||
// From multiple leptos::html::HTMLElement /////////////////////////////////////////
|
// // From multiple leptos::html::HTMLElement /////////////////////////////////////////
|
||||||
|
//
|
||||||
macro_rules! impl_from_multi_html_element {
|
// macro_rules! impl_from_multi_html_element {
|
||||||
($ty:ty) => {
|
// ($ty:ty) => {
|
||||||
impl<HtmlEl> From<&[HtmlElement<HtmlEl>]> for ElementsMaybeSignal<$ty, $ty>
|
// impl<E, At, Ch, Rndr> From<&[HtmlElement<E, At, Ch, Rndr>]>
|
||||||
where
|
// for ElementsMaybeSignal<$ty, $ty>
|
||||||
HtmlEl: ElementDescriptor + std::ops::Deref<Target = $ty>,
|
// where
|
||||||
{
|
// E: ElementType,
|
||||||
fn from(value: &[HtmlElement<HtmlEl>]) -> Self {
|
// E::Output: std::ops::Deref<Target = $ty>,
|
||||||
Self::Static(
|
// {
|
||||||
value
|
// fn from(value: &[HtmlElement<E, At, Ch, Rndr>]) -> Self {
|
||||||
.iter()
|
// Self::Static(
|
||||||
.map(|el| {
|
// value
|
||||||
let el: &$ty = el.deref();
|
// .iter()
|
||||||
Some(el.clone())
|
// .map(|el| {
|
||||||
})
|
// let el: &$ty = el.deref();
|
||||||
.collect(),
|
// Some(el.clone())
|
||||||
)
|
// })
|
||||||
}
|
// .collect(),
|
||||||
}
|
// )
|
||||||
|
// }
|
||||||
impl<HtmlEl, const C: usize> From<[HtmlElement<HtmlEl>; C]>
|
// }
|
||||||
for ElementsMaybeSignal<$ty, $ty>
|
//
|
||||||
where
|
// impl<E, At, Ch, Rndr, const C: usize> From<[HtmlElement<E, At, Ch, Rndr>; C]>
|
||||||
HtmlEl: ElementDescriptor + std::ops::Deref<Target = $ty>,
|
// for ElementsMaybeSignal<$ty, $ty>
|
||||||
{
|
// where
|
||||||
fn from(value: [HtmlElement<HtmlEl>; C]) -> Self {
|
// E: ElementType,
|
||||||
Self::Static(
|
// E::Output: std::ops::Deref<Target = $ty>,
|
||||||
value
|
// {
|
||||||
.iter()
|
// fn from(value: [HtmlElement<E, At, Ch, Rndr>; C]) -> Self {
|
||||||
.map(|el| {
|
// Self::Static(
|
||||||
let el: &$ty = el.deref();
|
// value
|
||||||
Some(el.clone())
|
// .iter()
|
||||||
})
|
// .map(|el| {
|
||||||
.collect(),
|
// let el: &$ty = el.deref();
|
||||||
)
|
// Some(el.clone())
|
||||||
}
|
// })
|
||||||
}
|
// .collect(),
|
||||||
|
// )
|
||||||
impl<HtmlEl> From<Vec<HtmlElement<HtmlEl>>> for ElementsMaybeSignal<$ty, $ty>
|
// }
|
||||||
where
|
// }
|
||||||
HtmlEl: ElementDescriptor + std::ops::Deref<Target = $ty>,
|
//
|
||||||
{
|
// impl<E, At, Ch, Rndr> From<Vec<HtmlElement<E, At, Ch, Rndr>>>
|
||||||
fn from(value: Vec<HtmlElement<HtmlEl>>) -> Self {
|
// for ElementsMaybeSignal<$ty, $ty>
|
||||||
Self::Static(
|
// where
|
||||||
value
|
// E: ElementType,
|
||||||
.iter()
|
// E::Output: std::ops::Deref<Target = $ty>,
|
||||||
.map(|el| {
|
// {
|
||||||
let el: &$ty = el.deref();
|
// fn from(value: Vec<HtmlElement<E, At, Ch, Rndr>>) -> Self {
|
||||||
Some(el.clone())
|
// Self::Static(
|
||||||
})
|
// value
|
||||||
.collect(),
|
// .iter()
|
||||||
)
|
// .map(|el| {
|
||||||
}
|
// let el: &$ty = el.deref();
|
||||||
}
|
// Some(el.clone())
|
||||||
};
|
// })
|
||||||
}
|
// .collect(),
|
||||||
|
// )
|
||||||
impl_from_multi_html_element!(web_sys::EventTarget);
|
// }
|
||||||
impl_from_multi_html_element!(web_sys::Element);
|
// }
|
||||||
|
// };
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// impl_from_multi_html_element!(web_sys::EventTarget);
|
||||||
|
// impl_from_multi_html_element!(web_sys::Element);
|
||||||
|
|
||||||
// From ElementMaybeSignal //////////////////////////////////////////////////////////////
|
// From ElementMaybeSignal //////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
@ -644,9 +661,11 @@ where
|
||||||
fn from(signal: ElementMaybeSignal<T, E>) -> Self {
|
fn from(signal: ElementMaybeSignal<T, E>) -> Self {
|
||||||
match signal {
|
match signal {
|
||||||
ElementMaybeSignal::Dynamic(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!(),
|
ElementMaybeSignal::_Phantom(_) => unreachable!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,16 +1,20 @@
|
||||||
use leptos::prelude::*;
|
use leptos::prelude::*;
|
||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
|
|
||||||
pub enum MaybeRwSignal<T>
|
pub enum MaybeRwSignal<T, S = SyncStorage>
|
||||||
where
|
where
|
||||||
T: 'static,
|
T: 'static,
|
||||||
|
S: Storage<T>,
|
||||||
{
|
{
|
||||||
Static(T),
|
Static(T),
|
||||||
DynamicRw(Signal<T>, WriteSignal<T>),
|
DynamicRw(Signal<T, S>, WriteSignal<T, S>),
|
||||||
DynamicRead(Signal<T>),
|
DynamicRead(Signal<T, S>),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Clone> Clone for MaybeRwSignal<T> {
|
impl<T: Clone, S> Clone for MaybeRwSignal<T, S>
|
||||||
|
where
|
||||||
|
S: Storage<T>,
|
||||||
|
{
|
||||||
fn clone(&self) -> Self {
|
fn clone(&self) -> Self {
|
||||||
match self {
|
match self {
|
||||||
Self::Static(t) => Self::Static(t.clone()),
|
Self::Static(t) => Self::Static(t.clone()),
|
||||||
|
@ -20,21 +24,21 @@ impl<T: Clone> Clone for MaybeRwSignal<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Copy> Copy for MaybeRwSignal<T> {}
|
impl<T: Copy, S> Copy for MaybeRwSignal<T, S> where S: Storage<T> {}
|
||||||
|
|
||||||
impl<T> From<T> for MaybeRwSignal<T> {
|
impl<T: Default, S> Default for MaybeRwSignal<T, S>
|
||||||
fn from(t: T) -> Self {
|
where
|
||||||
Self::Static(t)
|
S: Storage<T>,
|
||||||
}
|
{
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: Default> Default for MaybeRwSignal<T> {
|
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self::Static(T::default())
|
Self::Static(T::default())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Debug> Debug for MaybeRwSignal<T> {
|
impl<T: Debug, S> Debug for MaybeRwSignal<T, S>
|
||||||
|
where
|
||||||
|
S: Storage<T> + Debug,
|
||||||
|
{
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
Self::Static(t) => f.debug_tuple("Static").field(t).finish(),
|
Self::Static(t) => f.debug_tuple("Static").field(t).finish(),
|
||||||
|
@ -44,50 +48,172 @@ impl<T: Debug> Debug for MaybeRwSignal<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> From<Signal<T>> for MaybeRwSignal<T> {
|
impl<T> From<T> for MaybeRwSignal<T, SyncStorage>
|
||||||
|
where
|
||||||
|
SyncStorage: Storage<T>,
|
||||||
|
{
|
||||||
|
fn from(t: T) -> Self {
|
||||||
|
Self::Static(t)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> FromLocal<T> for MaybeRwSignal<T, LocalStorage>
|
||||||
|
where
|
||||||
|
LocalStorage: Storage<T>,
|
||||||
|
{
|
||||||
|
fn from_local(value: T) -> Self {
|
||||||
|
Self::Static(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> From<Signal<T>> for MaybeRwSignal<T>
|
||||||
|
where
|
||||||
|
SyncStorage: Storage<T>,
|
||||||
|
{
|
||||||
fn from(s: Signal<T>) -> Self {
|
fn from(s: Signal<T>) -> Self {
|
||||||
Self::DynamicRead(s)
|
Self::DynamicRead(s)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> From<ReadSignal<T>> for MaybeRwSignal<T> {
|
impl<T> FromLocal<Signal<T, LocalStorage>> for MaybeRwSignal<T, LocalStorage>
|
||||||
|
where
|
||||||
|
LocalStorage: Storage<T>,
|
||||||
|
{
|
||||||
|
fn from_local(s: Signal<T, LocalStorage>) -> Self {
|
||||||
|
Self::DynamicRead(s)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> From<ReadSignal<T>> for MaybeRwSignal<T>
|
||||||
|
where
|
||||||
|
T: Send + Sync,
|
||||||
|
{
|
||||||
fn from(s: ReadSignal<T>) -> Self {
|
fn from(s: ReadSignal<T>) -> Self {
|
||||||
Self::DynamicRead(s.into())
|
Self::DynamicRead(s.into())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> From<Memo<T>> for MaybeRwSignal<T> {
|
impl<T> FromLocal<ReadSignal<T, LocalStorage>> for MaybeRwSignal<T, LocalStorage>
|
||||||
|
where
|
||||||
|
LocalStorage: Storage<T>,
|
||||||
|
{
|
||||||
|
fn from_local(s: ReadSignal<T, LocalStorage>) -> Self {
|
||||||
|
Self::DynamicRead(s.into())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> From<Memo<T>> for MaybeRwSignal<T>
|
||||||
|
where
|
||||||
|
T: Send + Sync,
|
||||||
|
{
|
||||||
fn from(s: Memo<T>) -> Self {
|
fn from(s: Memo<T>) -> Self {
|
||||||
Self::DynamicRead(s.into())
|
Self::DynamicRead(s.into())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> From<RwSignal<T>> for MaybeRwSignal<T> {
|
impl<T> FromLocal<Memo<T, LocalStorage>> for MaybeRwSignal<T, LocalStorage>
|
||||||
|
where
|
||||||
|
LocalStorage: Storage<T>,
|
||||||
|
{
|
||||||
|
fn from_local(s: Memo<T, LocalStorage>) -> Self {
|
||||||
|
Self::DynamicRead(s.into())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> From<RwSignal<T>> for MaybeRwSignal<T>
|
||||||
|
where
|
||||||
|
T: Send + Sync,
|
||||||
|
{
|
||||||
fn from(s: RwSignal<T>) -> Self {
|
fn from(s: RwSignal<T>) -> Self {
|
||||||
let (r, w) = s.split();
|
let (r, w) = s.split();
|
||||||
Self::DynamicRw(r.into(), w)
|
Self::DynamicRw(r.into(), w)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> From<(ReadSignal<T>, WriteSignal<T>)> for MaybeRwSignal<T> {
|
impl<T> FromLocal<RwSignal<T, LocalStorage>> for MaybeRwSignal<T, LocalStorage>
|
||||||
|
where
|
||||||
|
LocalStorage: Storage<T>,
|
||||||
|
{
|
||||||
|
fn from_local(s: RwSignal<T, LocalStorage>) -> Self {
|
||||||
|
let (r, w) = s.split();
|
||||||
|
Self::DynamicRw(r.into(), w)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> From<(ReadSignal<T>, WriteSignal<T>)> for MaybeRwSignal<T>
|
||||||
|
where
|
||||||
|
T: Send + Sync,
|
||||||
|
{
|
||||||
fn from(s: (ReadSignal<T>, WriteSignal<T>)) -> Self {
|
fn from(s: (ReadSignal<T>, WriteSignal<T>)) -> Self {
|
||||||
Self::DynamicRw(s.0.into(), s.1)
|
Self::DynamicRw(s.0.into(), s.1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> From<(Signal<T>, WriteSignal<T>)> for MaybeRwSignal<T> {
|
impl<T> FromLocal<(ReadSignal<T, LocalStorage>, WriteSignal<T, LocalStorage>)>
|
||||||
|
for MaybeRwSignal<T, LocalStorage>
|
||||||
|
where
|
||||||
|
LocalStorage: Storage<T>,
|
||||||
|
{
|
||||||
|
fn from_local(s: (ReadSignal<T, LocalStorage>, WriteSignal<T, LocalStorage>)) -> Self {
|
||||||
|
Self::DynamicRw(s.0.into(), s.1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> From<(Signal<T>, WriteSignal<T>)> for MaybeRwSignal<T>
|
||||||
|
where
|
||||||
|
T: Send + Sync,
|
||||||
|
{
|
||||||
fn from(s: (Signal<T>, WriteSignal<T>)) -> Self {
|
fn from(s: (Signal<T>, WriteSignal<T>)) -> Self {
|
||||||
Self::DynamicRw(s.0, s.1)
|
Self::DynamicRw(s.0, s.1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<&str> for MaybeRwSignal<String> {
|
impl<T> FromLocal<(Signal<T, LocalStorage>, WriteSignal<T, LocalStorage>)>
|
||||||
|
for MaybeRwSignal<T, LocalStorage>
|
||||||
|
where
|
||||||
|
LocalStorage: Storage<T>,
|
||||||
|
{
|
||||||
|
fn from_local(s: (Signal<T, LocalStorage>, WriteSignal<T, LocalStorage>)) -> Self {
|
||||||
|
Self::DynamicRw(s.0, s.1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<S> From<&str> for MaybeRwSignal<String, S>
|
||||||
|
where
|
||||||
|
S: Storage<String>,
|
||||||
|
{
|
||||||
fn from(s: &str) -> Self {
|
fn from(s: &str) -> Self {
|
||||||
Self::Static(s.to_string())
|
Self::Static(s.to_string())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Clone> MaybeRwSignal<T> {
|
impl<T: Clone> MaybeRwSignal<T, LocalStorage> {
|
||||||
|
pub fn into_signal(self) -> (Signal<T, LocalStorage>, WriteSignal<T, LocalStorage>) {
|
||||||
|
match self {
|
||||||
|
Self::DynamicRead(s) => {
|
||||||
|
let (r, w) = signal_local(s.get_untracked());
|
||||||
|
|
||||||
|
Effect::<LocalStorage>::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<T: Clone> MaybeRwSignal<T>
|
||||||
|
where
|
||||||
|
T: Send + Sync,
|
||||||
|
{
|
||||||
pub fn into_signal(self) -> (Signal<T>, WriteSignal<T>) {
|
pub fn into_signal(self) -> (Signal<T>, WriteSignal<T>) {
|
||||||
match self {
|
match self {
|
||||||
Self::DynamicRead(s) => {
|
Self::DynamicRead(s) => {
|
||||||
|
|
|
@ -1,26 +1,42 @@
|
||||||
use leptos::prelude::*;
|
use leptos::prelude::*;
|
||||||
|
|
||||||
pub enum UseRwSignal<T: 'static> {
|
pub enum UseRwSignal<T: 'static, S = SyncStorage>
|
||||||
Separate(Signal<T>, WriteSignal<T>),
|
where
|
||||||
Combined(RwSignal<T>),
|
S: Storage<T>,
|
||||||
|
{
|
||||||
|
Separate(Signal<T, S>, WriteSignal<T, S>),
|
||||||
|
Combined(RwSignal<T, S>),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> From<RwSignal<T>> for UseRwSignal<T> {
|
impl<T, S> From<RwSignal<T, S>> for UseRwSignal<T, S>
|
||||||
fn from(s: RwSignal<T>) -> Self {
|
where
|
||||||
|
S: Storage<T>,
|
||||||
|
{
|
||||||
|
fn from(s: RwSignal<T, S>) -> Self {
|
||||||
Self::Combined(s)
|
Self::Combined(s)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T, RS> From<(RS, WriteSignal<T>)> for UseRwSignal<T>
|
impl<T, S, RS> From<(RS, WriteSignal<T, S>)> for UseRwSignal<T, S>
|
||||||
where
|
where
|
||||||
RS: Into<Signal<T>>,
|
RS: Into<Signal<T, S>>,
|
||||||
|
S: Storage<T>,
|
||||||
{
|
{
|
||||||
fn from(s: (RS, WriteSignal<T>)) -> Self {
|
fn from(s: (RS, WriteSignal<T, S>)) -> Self {
|
||||||
Self::Separate(s.0.into(), s.1)
|
Self::Separate(s.0.into(), s.1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> Default for UseRwSignal<T>
|
impl<T> Default for UseRwSignal<T>
|
||||||
|
where
|
||||||
|
T: Default + Send + Sync,
|
||||||
|
{
|
||||||
|
fn default() -> Self {
|
||||||
|
Self::Combined(Default::default())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> Default for UseRwSignal<T, LocalStorage>
|
||||||
where
|
where
|
||||||
T: Default,
|
T: Default,
|
||||||
{
|
{
|
||||||
|
@ -29,15 +45,21 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> Clone for UseRwSignal<T> {
|
impl<T, S> Clone for UseRwSignal<T, S>
|
||||||
|
where
|
||||||
|
S: Storage<T>,
|
||||||
|
{
|
||||||
fn clone(&self) -> Self {
|
fn clone(&self) -> Self {
|
||||||
*self
|
*self
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> Copy for UseRwSignal<T> {}
|
impl<T, S> Copy for UseRwSignal<T, S> where S: Storage<T> {}
|
||||||
|
|
||||||
impl<T> DefinedAt for UseRwSignal<T> {
|
impl<T, S> DefinedAt for UseRwSignal<T, S>
|
||||||
|
where
|
||||||
|
S: Storage<T>,
|
||||||
|
{
|
||||||
fn defined_at(&self) -> Option<&'static std::panic::Location<'static>> {
|
fn defined_at(&self) -> Option<&'static std::panic::Location<'static>> {
|
||||||
match self {
|
match self {
|
||||||
Self::Combined(s) => s.defined_at(),
|
Self::Combined(s) => s.defined_at(),
|
||||||
|
@ -47,7 +69,13 @@ impl<T> DefinedAt for UseRwSignal<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> With for UseRwSignal<T> {
|
impl<T, S> With for UseRwSignal<T, S>
|
||||||
|
where
|
||||||
|
RwSignal<T, S>: With<Value = T>,
|
||||||
|
Signal<T, S>: With<Value = T>,
|
||||||
|
ReadSignal<T, S>: With<Value = T>,
|
||||||
|
S: Storage<T>,
|
||||||
|
{
|
||||||
type Value = T;
|
type Value = T;
|
||||||
|
|
||||||
fn with<R>(&self, f: impl FnOnce(&T) -> R) -> R {
|
fn with<R>(&self, f: impl FnOnce(&T) -> R) -> R {
|
||||||
|
@ -65,7 +93,13 @@ impl<T> With for UseRwSignal<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> WithUntracked for UseRwSignal<T> {
|
impl<T, S> WithUntracked for UseRwSignal<T, S>
|
||||||
|
where
|
||||||
|
RwSignal<T, S>: WithUntracked<Value = T>,
|
||||||
|
Signal<T, S>: WithUntracked<Value = T>,
|
||||||
|
ReadSignal<T, S>: WithUntracked<Value = T>,
|
||||||
|
S: Storage<T>,
|
||||||
|
{
|
||||||
type Value = T;
|
type Value = T;
|
||||||
|
|
||||||
fn with_untracked<R>(&self, f: impl FnOnce(&T) -> R) -> R {
|
fn with_untracked<R>(&self, f: impl FnOnce(&T) -> R) -> R {
|
||||||
|
@ -83,7 +117,12 @@ impl<T> WithUntracked for UseRwSignal<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> Set for UseRwSignal<T> {
|
impl<T, S> Set for UseRwSignal<T, S>
|
||||||
|
where
|
||||||
|
RwSignal<T, S>: Set<Value = T>,
|
||||||
|
WriteSignal<T, S>: Set<Value = T>,
|
||||||
|
S: Storage<T>,
|
||||||
|
{
|
||||||
type Value = T;
|
type Value = T;
|
||||||
|
|
||||||
fn set(&self, new_value: T) {
|
fn set(&self, new_value: T) {
|
||||||
|
@ -101,7 +140,12 @@ impl<T> Set for UseRwSignal<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> Update for UseRwSignal<T> {
|
impl<T, S> Update for UseRwSignal<T, S>
|
||||||
|
where
|
||||||
|
RwSignal<T, S>: Update<Value = T>,
|
||||||
|
WriteSignal<T, S>: Update<Value = T>,
|
||||||
|
S: Storage<T>,
|
||||||
|
{
|
||||||
type Value = T;
|
type Value = T;
|
||||||
|
|
||||||
fn update(&self, f: impl FnOnce(&mut T)) {
|
fn update(&self, f: impl FnOnce(&mut T)) {
|
||||||
|
|
|
@ -28,7 +28,7 @@ mod on_click_outside;
|
||||||
mod signal_debounced;
|
mod signal_debounced;
|
||||||
mod signal_throttled;
|
mod signal_throttled;
|
||||||
mod sync_signal;
|
mod sync_signal;
|
||||||
mod use_active_element;
|
// mod use_active_element;
|
||||||
mod use_breakpoints;
|
mod use_breakpoints;
|
||||||
mod use_broadcast_channel;
|
mod use_broadcast_channel;
|
||||||
mod use_color_mode;
|
mod use_color_mode;
|
||||||
|
@ -94,7 +94,7 @@ pub use on_click_outside::*;
|
||||||
pub use signal_debounced::*;
|
pub use signal_debounced::*;
|
||||||
pub use signal_throttled::*;
|
pub use signal_throttled::*;
|
||||||
pub use sync_signal::*;
|
pub use sync_signal::*;
|
||||||
pub use use_active_element::*;
|
// pub use use_active_element::*;
|
||||||
pub use use_breakpoints::*;
|
pub use use_breakpoints::*;
|
||||||
pub use use_broadcast_channel::*;
|
pub use use_broadcast_channel::*;
|
||||||
pub use use_color_mode::*;
|
pub use use_color_mode::*;
|
||||||
|
@ -140,7 +140,6 @@ pub use use_throttle_fn::*;
|
||||||
pub use use_timeout_fn::*;
|
pub use use_timeout_fn::*;
|
||||||
pub use use_timestamp::*;
|
pub use use_timestamp::*;
|
||||||
pub use use_to_string::*;
|
pub use use_to_string::*;
|
||||||
pub use use_user_media::*;
|
|
||||||
pub use use_web_notification::*;
|
pub use use_web_notification::*;
|
||||||
pub use use_websocket::*;
|
pub use use_websocket::*;
|
||||||
pub use use_window::*;
|
pub use use_window::*;
|
||||||
|
|
|
@ -7,9 +7,9 @@ macro_rules! use_partial_cmp {
|
||||||
pub fn $fn_name<C, S, N>(container: S) -> Signal<Option<N>>
|
pub fn $fn_name<C, S, N>(container: S) -> Signal<Option<N>>
|
||||||
where
|
where
|
||||||
S: Into<MaybeSignal<C>>,
|
S: Into<MaybeSignal<C>>,
|
||||||
C: 'static,
|
C: Send + Sync + 'static,
|
||||||
for<'a> &'a C: IntoIterator<Item = &'a N>,
|
for<'a> &'a C: IntoIterator<Item = &'a N>,
|
||||||
N: PartialOrd + Clone,
|
N: PartialOrd + Clone + Send + Sync,
|
||||||
{
|
{
|
||||||
let container = container.into();
|
let container = container.into();
|
||||||
|
|
||||||
|
@ -47,8 +47,8 @@ macro_rules! use_simple_math {
|
||||||
$(#[$outer])*
|
$(#[$outer])*
|
||||||
pub fn [<use_ $fn_name>]<S, N>(x: S) -> Signal<N>
|
pub fn [<use_ $fn_name>]<S, N>(x: S) -> Signal<N>
|
||||||
where
|
where
|
||||||
S: Into<MaybeSignal<N>>,
|
S: Into<MaybeSignal<N>> + Send + Sync,
|
||||||
N: Float,
|
N: Float + Send + Sync,
|
||||||
{
|
{
|
||||||
let x = x.into();
|
let x = x.into();
|
||||||
Signal::derive(move || x.get().$fn_name())
|
Signal::derive(move || x.get().$fn_name())
|
||||||
|
|
|
@ -20,7 +20,7 @@ pub fn use_local_storage<T, C>(
|
||||||
key: impl AsRef<str>,
|
key: impl AsRef<str>,
|
||||||
) -> (Signal<T>, WriteSignal<T>, impl Fn() + Clone)
|
) -> (Signal<T>, WriteSignal<T>, impl Fn() + Clone)
|
||||||
where
|
where
|
||||||
T: Clone + Default + PartialEq + Send + Sync,
|
T: Clone + Default + PartialEq + Send + Sync + 'static,
|
||||||
C: Encoder<T, Encoded = String> + Decoder<T, Encoded = str>,
|
C: Encoder<T, Encoded = String> + Decoder<T, Encoded = str>,
|
||||||
{
|
{
|
||||||
use_storage_with_options::<T, C>(
|
use_storage_with_options::<T, C>(
|
||||||
|
|
|
@ -14,7 +14,7 @@ pub fn use_session_storage<T, C>(
|
||||||
key: impl AsRef<str>,
|
key: impl AsRef<str>,
|
||||||
) -> (Signal<T>, WriteSignal<T>, impl Fn() + Clone)
|
) -> (Signal<T>, WriteSignal<T>, impl Fn() + Clone)
|
||||||
where
|
where
|
||||||
T: Clone + Default + PartialEq + Send + Sync,
|
T: Clone + Default + PartialEq + Send + Sync + 'static,
|
||||||
C: Encoder<T, Encoded = String> + Decoder<T, Encoded = str>,
|
C: Encoder<T, Encoded = String> + Decoder<T, Encoded = str>,
|
||||||
{
|
{
|
||||||
use_storage_with_options::<T, C>(
|
use_storage_with_options::<T, C>(
|
||||||
|
|
|
@ -6,6 +6,7 @@ use codee::{CodecError, Decoder, Encoder};
|
||||||
use default_struct_builder::DefaultBuilder;
|
use default_struct_builder::DefaultBuilder;
|
||||||
use leptos::prelude::wrappers::read::Signal;
|
use leptos::prelude::wrappers::read::Signal;
|
||||||
use leptos::prelude::*;
|
use leptos::prelude::*;
|
||||||
|
use send_wrapper::SendWrapper;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
use wasm_bindgen::JsValue;
|
use wasm_bindgen::JsValue;
|
||||||
|
@ -151,7 +152,7 @@ pub fn use_storage<T, C>(
|
||||||
key: impl AsRef<str>,
|
key: impl AsRef<str>,
|
||||||
) -> (Signal<T>, WriteSignal<T>, impl Fn() + Clone)
|
) -> (Signal<T>, WriteSignal<T>, impl Fn() + Clone)
|
||||||
where
|
where
|
||||||
T: Default + Clone + PartialEq + Send + Sync,
|
T: Default + Clone + PartialEq + Send + Sync + 'static,
|
||||||
C: Encoder<T, Encoded = String> + Decoder<T, Encoded = str>,
|
C: Encoder<T, Encoded = String> + Decoder<T, Encoded = str>,
|
||||||
{
|
{
|
||||||
use_storage_with_options::<T, C>(storage_type, key, UseStorageOptions::default())
|
use_storage_with_options::<T, C>(storage_type, key, UseStorageOptions::default())
|
||||||
|
@ -238,7 +239,7 @@ where
|
||||||
let key = key.as_ref().to_owned();
|
let key = key.as_ref().to_owned();
|
||||||
let on_error = on_error.to_owned();
|
let on_error = on_error.to_owned();
|
||||||
|
|
||||||
move || {
|
SendWrapper::new(move || {
|
||||||
let fetched = storage
|
let fetched = storage
|
||||||
.to_owned()
|
.to_owned()
|
||||||
.and_then(|storage| {
|
.and_then(|storage| {
|
||||||
|
@ -270,14 +271,15 @@ where
|
||||||
// Revert to default
|
// Revert to default
|
||||||
None => set_data.set(default.clone()),
|
None => set_data.set(default.clone()),
|
||||||
};
|
};
|
||||||
}
|
})
|
||||||
};
|
};
|
||||||
|
|
||||||
// Fires when storage needs to be fetched
|
// Fires when storage needs to be fetched
|
||||||
let notify = Trigger::new();
|
let notify = ArcTrigger::new();
|
||||||
|
|
||||||
// Refetch from storage. Keeps track of how many times we've been notified. Does not increment for calls to set_data
|
// Refetch from storage. Keeps track of how many times we've been notified. Does not increment for calls to set_data
|
||||||
let notify_id = Memo::<usize>::new({
|
let notify_id = Memo::<usize>::new({
|
||||||
|
let notify = notify.clone();
|
||||||
let fetch_from_storage = fetch_from_storage.clone();
|
let fetch_from_storage = fetch_from_storage.clone();
|
||||||
|
|
||||||
move |prev| {
|
move |prev| {
|
||||||
|
@ -327,31 +329,43 @@ where
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fetch initial value
|
if delay_during_hydration
|
||||||
if delay_during_hydration && leptos::leptos_dom::HydrationCtx::is_hydrating() {
|
&& Owner::current_shared_context()
|
||||||
request_animation_frame(fetch_from_storage.clone());
|
.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 {
|
} else {
|
||||||
fetch_from_storage();
|
fetch_from_storage();
|
||||||
}
|
}
|
||||||
|
|
||||||
if listen_to_storage_changes {
|
if listen_to_storage_changes {
|
||||||
let check_key = key.as_ref().to_owned();
|
let check_key = key.as_ref().to_owned();
|
||||||
|
let storage_notify = notify.clone();
|
||||||
|
let custom_notify = notify.clone();
|
||||||
|
|
||||||
// Listen to global storage events
|
// Listen to global storage events
|
||||||
let _ = use_event_listener(use_window(), leptos::ev::storage, move |ev| {
|
let _ = use_event_listener(use_window(), leptos::ev::storage, move |ev| {
|
||||||
let ev_key = ev.key();
|
let ev_key = ev.key();
|
||||||
// Key matches or all keys deleted (None)
|
// Key matches or all keys deleted (None)
|
||||||
if ev_key == Some(check_key.clone()) || ev_key.is_none() {
|
if ev_key == Some(check_key.clone()) || ev_key.is_none() {
|
||||||
notify.notify()
|
storage_notify.trigger()
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
// Listen to internal storage events
|
// Listen to internal storage events
|
||||||
let check_key = key.as_ref().to_owned();
|
let check_key = key.as_ref().to_owned();
|
||||||
let _ = use_event_listener(
|
let _ = use_event_listener(
|
||||||
use_window(),
|
use_window(),
|
||||||
ev::Custom::new(INTERNAL_STORAGE_EVENT),
|
leptos::ev::Custom::new(INTERNAL_STORAGE_EVENT),
|
||||||
move |ev: web_sys::CustomEvent| {
|
{
|
||||||
if Some(check_key.clone()) == ev.detail().as_string() {
|
move |ev: web_sys::CustomEvent| {
|
||||||
notify.notify()
|
if Some(check_key.clone()) == ev.detail().as_string() {
|
||||||
|
custom_notify.trigger()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
@ -365,9 +379,9 @@ where
|
||||||
// Delete directly from storage
|
// Delete directly from storage
|
||||||
let result = storage
|
let result = storage
|
||||||
.remove_item(&key)
|
.remove_item(&key)
|
||||||
.map_err(UseStorageError::RemoveItemFailed);
|
.map_err(|e| UseStorageError::RemoveItemFailed(e));
|
||||||
let _ = handle_error(&on_error, result);
|
let _ = handle_error(&on_error, result);
|
||||||
notify.notify();
|
notify.trigger();
|
||||||
dispatch_storage_event();
|
dispatch_storage_event();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -400,11 +414,11 @@ pub enum UseStorageError<E, D> {
|
||||||
#[derive(DefaultBuilder)]
|
#[derive(DefaultBuilder)]
|
||||||
pub struct UseStorageOptions<T, E, D>
|
pub struct UseStorageOptions<T, E, D>
|
||||||
where
|
where
|
||||||
T: 'static,
|
T: Send + Sync + 'static,
|
||||||
{
|
{
|
||||||
// Callback for when an error occurs
|
// Callback for when an error occurs
|
||||||
#[builder(skip)]
|
#[builder(skip)]
|
||||||
on_error: Arc<dyn Fn(UseStorageError<E, D>)>,
|
on_error: Arc<dyn Fn(UseStorageError<E, D>) + Send + Sync>,
|
||||||
// Whether to continuously listen to changes from browser storage
|
// Whether to continuously listen to changes from browser storage
|
||||||
listen_to_storage_changes: bool,
|
listen_to_storage_changes: bool,
|
||||||
// Initial value to use when the storage key is not set
|
// Initial value to use when the storage key is not set
|
||||||
|
@ -422,13 +436,16 @@ where
|
||||||
/// Calls the on_error callback with the given error. Removes the error from the Result to avoid double error handling.
|
/// Calls the on_error callback with the given error. Removes the error from the Result to avoid double error handling.
|
||||||
#[cfg(not(feature = "ssr"))]
|
#[cfg(not(feature = "ssr"))]
|
||||||
fn handle_error<T, E, D>(
|
fn handle_error<T, E, D>(
|
||||||
on_error: &Arc<dyn Fn(UseStorageError<E, D>)>,
|
on_error: &Arc<dyn Fn(UseStorageError<E, D>) + Send + Sync>,
|
||||||
result: Result<T, UseStorageError<E, D>>,
|
result: Result<T, UseStorageError<E, D>>,
|
||||||
) -> Result<T, ()> {
|
) -> Result<T, ()> {
|
||||||
result.map_err(|err| (on_error)(err))
|
result.map_err(|err| (on_error)(err))
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Default, E, D> Default for UseStorageOptions<T, E, D> {
|
impl<T: Default, E, D> Default for UseStorageOptions<T, E, D>
|
||||||
|
where
|
||||||
|
T: Send + Sync + 'static,
|
||||||
|
{
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
on_error: Arc::new(|_err| ()),
|
on_error: Arc::new(|_err| ()),
|
||||||
|
@ -440,9 +457,15 @@ impl<T: Default, E, D> Default for UseStorageOptions<T, E, D> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Default, E, D> UseStorageOptions<T, E, D> {
|
impl<T: Default, E, D> UseStorageOptions<T, E, D>
|
||||||
|
where
|
||||||
|
T: Send + Sync + 'static,
|
||||||
|
{
|
||||||
/// Optional callback whenever an error occurs.
|
/// Optional callback whenever an error occurs.
|
||||||
pub fn on_error(self, on_error: impl Fn(UseStorageError<E, D>) + 'static) -> Self {
|
pub fn on_error(
|
||||||
|
self,
|
||||||
|
on_error: impl Fn(UseStorageError<E, D>) + Send + Sync + 'static,
|
||||||
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
on_error: Arc::new(on_error),
|
on_error: Arc::new(on_error),
|
||||||
..self
|
..self
|
||||||
|
|
|
@ -148,7 +148,7 @@ pub fn sync_signal<T>(
|
||||||
right: impl Into<UseRwSignal<T>>,
|
right: impl Into<UseRwSignal<T>>,
|
||||||
) -> impl Fn() + Clone
|
) -> impl Fn() + Clone
|
||||||
where
|
where
|
||||||
T: Clone + PartialEq + 'static,
|
T: Clone + PartialEq + Send + Sync + 'static,
|
||||||
{
|
{
|
||||||
sync_signal_with_options(left, right, SyncSignalOptions::default())
|
sync_signal_with_options(left, right, SyncSignalOptions::default())
|
||||||
}
|
}
|
||||||
|
@ -160,8 +160,8 @@ pub fn sync_signal_with_options<L, R>(
|
||||||
options: SyncSignalOptions<L, R>,
|
options: SyncSignalOptions<L, R>,
|
||||||
) -> impl Fn() + Clone
|
) -> impl Fn() + Clone
|
||||||
where
|
where
|
||||||
L: Clone + PartialEq + 'static,
|
L: Clone + PartialEq + Send + Sync + 'static,
|
||||||
R: Clone + PartialEq + 'static,
|
R: Clone + PartialEq + Send + Sync + 'static,
|
||||||
{
|
{
|
||||||
let SyncSignalOptions {
|
let SyncSignalOptions {
|
||||||
immediate,
|
immediate,
|
||||||
|
|
|
@ -111,7 +111,7 @@ use std::hash::Hash;
|
||||||
///
|
///
|
||||||
/// Since internally this uses [`fn@crate::use_media_query`], which returns always `false` on the server,
|
/// Since internally this uses [`fn@crate::use_media_query`], which returns always `false` on the server,
|
||||||
/// the returned methods also will return `false`.
|
/// the returned methods also will return `false`.
|
||||||
pub fn use_breakpoints<K: Eq + Hash + Debug + Clone>(
|
pub fn use_breakpoints<K: Eq + Hash + Debug + Clone + Send + Sync>(
|
||||||
breakpoints: HashMap<K, u32>,
|
breakpoints: HashMap<K, u32>,
|
||||||
) -> UseBreakpointsReturn<K> {
|
) -> UseBreakpointsReturn<K> {
|
||||||
UseBreakpointsReturn { breakpoints }
|
UseBreakpointsReturn { breakpoints }
|
||||||
|
@ -119,7 +119,7 @@ pub fn use_breakpoints<K: Eq + Hash + Debug + Clone>(
|
||||||
|
|
||||||
/// Return type of [`use_breakpoints`]
|
/// Return type of [`use_breakpoints`]
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct UseBreakpointsReturn<K: Eq + Hash + Debug + Clone> {
|
pub struct UseBreakpointsReturn<K: Eq + Hash + Debug + Clone + Send + Sync> {
|
||||||
breakpoints: HashMap<K, u32>,
|
breakpoints: HashMap<K, u32>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -185,7 +185,10 @@ macro_rules! impl_cmp_reactively {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<K: Eq + Hash + Debug + Clone> UseBreakpointsReturn<K> {
|
impl<K> UseBreakpointsReturn<K>
|
||||||
|
where
|
||||||
|
K: Eq + Hash + Debug + Clone + Send + Sync + 'static,
|
||||||
|
{
|
||||||
fn match_(query: &str) -> bool {
|
fn match_(query: &str) -> bool {
|
||||||
if let Ok(Some(query_list)) = use_window().match_media(query) {
|
if let Ok(Some(query_list)) = use_window().match_media(query) {
|
||||||
return query_list.matches();
|
return query_list.matches();
|
||||||
|
|
|
@ -80,14 +80,17 @@ pub fn use_broadcast_channel<T, C>(
|
||||||
<C as Decoder<T>>::Error,
|
<C as Decoder<T>>::Error,
|
||||||
>
|
>
|
||||||
where
|
where
|
||||||
|
T: Send + Sync,
|
||||||
C: Encoder<T, Encoded = String> + Decoder<T, Encoded = str>,
|
C: Encoder<T, Encoded = String> + Decoder<T, Encoded = str>,
|
||||||
|
<C as Encoder<T>>::Error: Send + Sync,
|
||||||
|
<C as Decoder<T>>::Error: Send + Sync,
|
||||||
{
|
{
|
||||||
let is_supported = use_supported(|| js!("BroadcastChannel" in &window()));
|
let is_supported = use_supported(|| js!("BroadcastChannel" in &window()));
|
||||||
|
|
||||||
let (is_closed, set_closed) = signal(false);
|
let (is_closed, set_closed) = signal(false);
|
||||||
let (channel, set_channel) = signal(None::<web_sys::BroadcastChannel>);
|
let (channel, set_channel) = signal_local(None::<web_sys::BroadcastChannel>);
|
||||||
let (message, set_message) = signal(None::<T>);
|
let (message, set_message) = signal(None::<T>);
|
||||||
let (error, set_error) = signal(
|
let (error, set_error) = signal_local(
|
||||||
None::<UseBroadcastChannelError<<C as Encoder<T>>::Error, <C as Decoder<T>>::Error>>,
|
None::<UseBroadcastChannelError<<C as Encoder<T>>::Error, <C as Decoder<T>>::Error>>,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -178,17 +181,17 @@ where
|
||||||
/// Return type of [`use_broadcast_channel`].
|
/// Return type of [`use_broadcast_channel`].
|
||||||
pub struct UseBroadcastChannelReturn<T, PFn, CFn, E, D>
|
pub struct UseBroadcastChannelReturn<T, PFn, CFn, E, D>
|
||||||
where
|
where
|
||||||
T: 'static,
|
T: Send + Sync + 'static,
|
||||||
PFn: Fn(&T) + Clone,
|
PFn: Fn(&T) + Clone,
|
||||||
CFn: Fn() + Clone,
|
CFn: Fn() + Clone,
|
||||||
E: 'static,
|
E: Send + Sync + 'static,
|
||||||
D: 'static,
|
D: Send + Sync + 'static,
|
||||||
{
|
{
|
||||||
/// `true` if this browser supports `BroadcastChannel`s.
|
/// `true` if this browser supports `BroadcastChannel`s.
|
||||||
pub is_supported: Signal<bool>,
|
pub is_supported: Signal<bool>,
|
||||||
|
|
||||||
/// The broadcast channel that is wrapped by this function
|
/// The broadcast channel that is wrapped by this function
|
||||||
pub channel: Signal<Option<web_sys::BroadcastChannel>>,
|
pub channel: Signal<Option<web_sys::BroadcastChannel>, LocalStorage>,
|
||||||
|
|
||||||
/// Latest message received from the channel
|
/// Latest message received from the channel
|
||||||
pub message: Signal<Option<T>>,
|
pub message: Signal<Option<T>>,
|
||||||
|
@ -200,7 +203,7 @@ where
|
||||||
pub close: CFn,
|
pub close: CFn,
|
||||||
|
|
||||||
/// Latest error as reported by the `messageerror` event.
|
/// Latest error as reported by the `messageerror` event.
|
||||||
pub error: Signal<Option<UseBroadcastChannelError<E, D>>>,
|
pub error: Signal<Option<UseBroadcastChannelError<E, D>>, LocalStorage>,
|
||||||
|
|
||||||
/// Wether the channel is closed
|
/// Wether the channel is closed
|
||||||
pub is_closed: Signal<bool>,
|
pub is_closed: Signal<bool>,
|
||||||
|
|
|
@ -79,7 +79,7 @@ pub fn use_clipboard_with_options(
|
||||||
|
|
||||||
let update_text = move |_| {
|
let update_text = move |_| {
|
||||||
if is_supported.get() {
|
if is_supported.get() {
|
||||||
spawn_local(async move {
|
leptos::spawn::spawn_local(async move {
|
||||||
if let Some(clipboard) = window().navigator().clipboard() {
|
if let Some(clipboard) = window().navigator().clipboard() {
|
||||||
if let Ok(text) = js_fut!(clipboard.read_text()).await {
|
if let Ok(text) = js_fut!(clipboard.read_text()).await {
|
||||||
set_text.set(text.as_string());
|
set_text.set(text.as_string());
|
||||||
|
@ -102,7 +102,7 @@ pub fn use_clipboard_with_options(
|
||||||
let start = start.clone();
|
let start = start.clone();
|
||||||
let value = value.to_owned();
|
let value = value.to_owned();
|
||||||
|
|
||||||
spawn_local(async move {
|
leptos::spawn::spawn_local(async move {
|
||||||
if let Some(clipboard) = window().navigator().clipboard() {
|
if let Some(clipboard) = window().navigator().clipboard() {
|
||||||
if js_fut!(clipboard.write_text(&value)).await.is_ok() {
|
if js_fut!(clipboard.write_text(&value)).await.is_ok() {
|
||||||
set_text.set(Some(value));
|
set_text.set(Some(value));
|
||||||
|
|
|
@ -9,8 +9,8 @@ use leptos::prelude::wrappers::read::Signal;
|
||||||
use leptos::prelude::*;
|
use leptos::prelude::*;
|
||||||
use std::fmt::{Display, Formatter};
|
use std::fmt::{Display, Formatter};
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
use std::rc::Rc;
|
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
use std::sync::Arc;
|
||||||
use wasm_bindgen::JsCast;
|
use wasm_bindgen::JsCast;
|
||||||
|
|
||||||
/// Reactive color mode (dark / light / customs) with auto data persistence.
|
/// Reactive color mode (dark / light / customs) with auto data persistence.
|
||||||
|
@ -209,7 +209,7 @@ where
|
||||||
if initial_value_from_url_param_to_storage {
|
if initial_value_from_url_param_to_storage {
|
||||||
set_store.set(value);
|
set_store.set(value);
|
||||||
} else {
|
} else {
|
||||||
set_store.set_untracked(value);
|
*set_store.write_untracked() = value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -279,7 +279,7 @@ where
|
||||||
};
|
};
|
||||||
|
|
||||||
let on_changed = move |mode: ColorMode| {
|
let on_changed = move |mode: ColorMode| {
|
||||||
on_changed(mode, Rc::new(default_on_changed.clone()));
|
on_changed(mode, Arc::new(default_on_changed.clone()));
|
||||||
};
|
};
|
||||||
|
|
||||||
Effect::new({
|
Effect::new({
|
||||||
|
@ -427,7 +427,7 @@ where
|
||||||
/// To get the default behaviour back you can call the provided `default_handler` function.
|
/// To get the default behaviour back you can call the provided `default_handler` function.
|
||||||
/// It takes two parameters:
|
/// It takes two parameters:
|
||||||
/// - `mode: ColorMode`: The color mode to change to.
|
/// - `mode: ColorMode`: The color mode to change to.
|
||||||
/// - `default_handler: Rc<dyn Fn(ColorMode)>`: The default handler that would have been called if the `on_changed` handler had not been specified.
|
/// -`default_handler: Arc<dyn Fn(ColorMode)>`: The default handler that would have been called if the `on_changed` handler had not been specified.
|
||||||
on_changed: OnChangedFn,
|
on_changed: OnChangedFn,
|
||||||
|
|
||||||
/// When provided, `useStorage` will be skipped.
|
/// When provided, `useStorage` will be skipped.
|
||||||
|
@ -476,7 +476,7 @@ where
|
||||||
_marker: PhantomData<T>,
|
_marker: PhantomData<T>,
|
||||||
}
|
}
|
||||||
|
|
||||||
type OnChangedFn = Rc<dyn Fn(ColorMode, Rc<dyn Fn(ColorMode)>)>;
|
type OnChangedFn = Arc<dyn Fn(ColorMode, Arc<dyn Fn(ColorMode) + Send + Sync>) + Send + Sync>;
|
||||||
|
|
||||||
impl Default for UseColorModeOptions<&'static str, web_sys::Element> {
|
impl Default for UseColorModeOptions<&'static str, web_sys::Element> {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
|
@ -487,7 +487,7 @@ impl Default for UseColorModeOptions<&'static str, web_sys::Element> {
|
||||||
initial_value_from_url_param: None,
|
initial_value_from_url_param: None,
|
||||||
initial_value_from_url_param_to_storage: false,
|
initial_value_from_url_param_to_storage: false,
|
||||||
custom_modes: vec![],
|
custom_modes: vec![],
|
||||||
on_changed: Rc::new(move |mode, default_handler| (default_handler)(mode)),
|
on_changed: Arc::new(move |mode, default_handler| (default_handler)(mode)),
|
||||||
storage_signal: None,
|
storage_signal: None,
|
||||||
storage_key: "leptos-use-color-scheme".into(),
|
storage_key: "leptos-use-color-scheme".into(),
|
||||||
storage: StorageType::default(),
|
storage: StorageType::default(),
|
||||||
|
|
|
@ -7,7 +7,7 @@ pub use cookie::SameSite;
|
||||||
use cookie::{Cookie, CookieJar};
|
use cookie::{Cookie, CookieJar};
|
||||||
use default_struct_builder::DefaultBuilder;
|
use default_struct_builder::DefaultBuilder;
|
||||||
use leptos::prelude::*;
|
use leptos::prelude::*;
|
||||||
use std::rc::Rc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
/// SSR-friendly and reactive cookie access.
|
/// SSR-friendly and reactive cookie access.
|
||||||
///
|
///
|
||||||
|
@ -139,7 +139,7 @@ use std::rc::Rc;
|
||||||
pub fn use_cookie<T, C>(cookie_name: &str) -> (Signal<Option<T>>, WriteSignal<Option<T>>)
|
pub fn use_cookie<T, C>(cookie_name: &str) -> (Signal<Option<T>>, WriteSignal<Option<T>>)
|
||||||
where
|
where
|
||||||
C: Encoder<T, Encoded = String> + Decoder<T, Encoded = str>,
|
C: Encoder<T, Encoded = String> + Decoder<T, Encoded = str>,
|
||||||
T: Clone,
|
T: Clone + Send + Sync + 'static,
|
||||||
{
|
{
|
||||||
use_cookie_with_options::<T, C>(cookie_name, UseCookieOptions::default())
|
use_cookie_with_options::<T, C>(cookie_name, UseCookieOptions::default())
|
||||||
}
|
}
|
||||||
|
@ -151,7 +151,7 @@ pub fn use_cookie_with_options<T, C>(
|
||||||
) -> (Signal<Option<T>>, WriteSignal<Option<T>>)
|
) -> (Signal<Option<T>>, WriteSignal<Option<T>>)
|
||||||
where
|
where
|
||||||
C: Encoder<T, Encoded = String> + Decoder<T, Encoded = str>,
|
C: Encoder<T, Encoded = String> + Decoder<T, Encoded = str>,
|
||||||
T: Clone,
|
T: Clone + Send + Sync + 'static,
|
||||||
{
|
{
|
||||||
let UseCookieOptions {
|
let UseCookieOptions {
|
||||||
max_age,
|
max_age,
|
||||||
|
@ -185,7 +185,7 @@ where
|
||||||
let jar = StoredValue::new(CookieJar::new());
|
let jar = StoredValue::new(CookieJar::new());
|
||||||
|
|
||||||
if !has_expired {
|
if !has_expired {
|
||||||
let ssr_cookies_header_getter = Rc::clone(&ssr_cookies_header_getter);
|
let ssr_cookies_header_getter = Arc::clone(&ssr_cookies_header_getter);
|
||||||
|
|
||||||
jar.update_value(|jar| {
|
jar.update_value(|jar| {
|
||||||
if let Some(new_jar) = load_and_parse_cookie_jar(ssr_cookies_header_getter) {
|
if let Some(new_jar) = load_and_parse_cookie_jar(ssr_cookies_header_getter) {
|
||||||
|
@ -225,8 +225,8 @@ where
|
||||||
|
|
||||||
let on_cookie_change = {
|
let on_cookie_change = {
|
||||||
let cookie_name = cookie_name.to_owned();
|
let cookie_name = cookie_name.to_owned();
|
||||||
let ssr_cookies_header_getter = Rc::clone(&ssr_cookies_header_getter);
|
let ssr_cookies_header_getter = Arc::clone(&ssr_cookies_header_getter);
|
||||||
let on_error = Rc::clone(&on_error);
|
let on_error = Arc::clone(&on_error);
|
||||||
let domain = domain.clone();
|
let domain = domain.clone();
|
||||||
let path = path.clone();
|
let path = path.clone();
|
||||||
|
|
||||||
|
@ -261,7 +261,7 @@ where
|
||||||
same_site,
|
same_site,
|
||||||
secure,
|
secure,
|
||||||
http_only,
|
http_only,
|
||||||
Rc::clone(&ssr_cookies_header_getter),
|
Arc::clone(&ssr_cookies_header_getter),
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -284,7 +284,7 @@ where
|
||||||
|
|
||||||
// listen to cookie changes from the broadcast channel
|
// listen to cookie changes from the broadcast channel
|
||||||
Effect::new({
|
Effect::new({
|
||||||
let ssr_cookies_header_getter = Rc::clone(&ssr_cookies_header_getter);
|
let ssr_cookies_header_getter = Arc::clone(&ssr_cookies_header_getter);
|
||||||
let cookie_name = cookie_name.to_owned();
|
let cookie_name = cookie_name.to_owned();
|
||||||
|
|
||||||
move |_| {
|
move |_| {
|
||||||
|
@ -295,7 +295,7 @@ where
|
||||||
match C::decode(&message) {
|
match C::decode(&message) {
|
||||||
Ok(value) => {
|
Ok(value) => {
|
||||||
let ssr_cookies_header_getter =
|
let ssr_cookies_header_getter =
|
||||||
Rc::clone(&ssr_cookies_header_getter);
|
Arc::clone(&ssr_cookies_header_getter);
|
||||||
|
|
||||||
jar.update_value(|jar| {
|
jar.update_value(|jar| {
|
||||||
update_client_cookie_jar(
|
update_client_cookie_jar(
|
||||||
|
@ -321,7 +321,7 @@ where
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
let cookie_name = cookie_name.clone();
|
let cookie_name = cookie_name.clone();
|
||||||
let ssr_cookies_header_getter = Rc::clone(&ssr_cookies_header_getter);
|
let ssr_cookies_header_getter = Arc::clone(&ssr_cookies_header_getter);
|
||||||
|
|
||||||
jar.update_value(|jar| {
|
jar.update_value(|jar| {
|
||||||
update_client_cookie_jar(
|
update_client_cookie_jar(
|
||||||
|
@ -359,25 +359,24 @@ where
|
||||||
#[cfg(feature = "ssr")]
|
#[cfg(feature = "ssr")]
|
||||||
{
|
{
|
||||||
if !readonly {
|
if !readonly {
|
||||||
let cookie_name = cookie_name.to_owned();
|
Effect::new_isomorphic({
|
||||||
|
let cookie_name = cookie_name.to_owned();
|
||||||
|
let ssr_set_cookie = Arc::clone(&ssr_set_cookie);
|
||||||
|
|
||||||
create_isomorphic_effect(move |_| {
|
move |_| {
|
||||||
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({
|
|
||||||
let domain = domain.clone();
|
let domain = domain.clone();
|
||||||
let path = path.clone();
|
let path = path.clone();
|
||||||
let ssr_set_cookie = Rc::clone(&ssr_set_cookie);
|
|
||||||
|
|
||||||
|jar| {
|
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(
|
write_server_cookie(
|
||||||
&cookie_name,
|
&cookie_name,
|
||||||
value,
|
value,
|
||||||
|
@ -389,10 +388,10 @@ where
|
||||||
same_site,
|
same_site,
|
||||||
secure,
|
secure,
|
||||||
http_only,
|
http_only,
|
||||||
ssr_set_cookie,
|
Arc::clone(&ssr_set_cookie),
|
||||||
)
|
)
|
||||||
}
|
});
|
||||||
});
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -472,14 +471,14 @@ pub struct UseCookieOptions<T, E, D> {
|
||||||
|
|
||||||
/// Getter function to return the string value of the cookie header.
|
/// Getter function to return the string value of the cookie header.
|
||||||
/// When you use one of the features `"axum"`, `"actix"` or `"spin"` there's a valid default implementation provided.
|
/// When you use one of the features `"axum"`, `"actix"` or `"spin"` there's a valid default implementation provided.
|
||||||
ssr_cookies_header_getter: Rc<dyn Fn() -> Option<String>>,
|
ssr_cookies_header_getter: Arc<dyn Fn() -> Option<String> + Send + Sync>,
|
||||||
|
|
||||||
/// Function to add a set cookie header to the response on the server.
|
/// Function to add a set cookie header to the response on the server.
|
||||||
/// When you use one of the features `"axum"`, `"actix"` or `"spin"` there's a valid default implementation provided.
|
/// When you use one of the features `"axum"`, `"actix"` or `"spin"` there's a valid default implementation provided.
|
||||||
ssr_set_cookie: Rc<dyn Fn(&Cookie)>,
|
ssr_set_cookie: Arc<dyn Fn(&Cookie) + Send + Sync>,
|
||||||
|
|
||||||
/// Callback for encoding/decoding errors. Defaults to logging the error to the console.
|
/// Callback for encoding/decoding errors. Defaults to logging the error to the console.
|
||||||
on_error: Rc<dyn Fn(CodecError<E, D>)>,
|
on_error: Arc<dyn Fn(CodecError<E, D>) + Send + Sync>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T, E, D> Default for UseCookieOptions<T, E, D> {
|
impl<T, E, D> Default for UseCookieOptions<T, E, D> {
|
||||||
|
@ -495,7 +494,7 @@ impl<T, E, D> Default for UseCookieOptions<T, E, D> {
|
||||||
domain: None,
|
domain: None,
|
||||||
path: None,
|
path: None,
|
||||||
same_site: None,
|
same_site: None,
|
||||||
ssr_cookies_header_getter: Rc::new(move || {
|
ssr_cookies_header_getter: Arc::new(move || {
|
||||||
#[cfg(feature = "ssr")]
|
#[cfg(feature = "ssr")]
|
||||||
{
|
{
|
||||||
#[cfg(all(feature = "actix", feature = "axum"))]
|
#[cfg(all(feature = "actix", feature = "axum"))]
|
||||||
|
@ -569,7 +568,7 @@ impl<T, E, D> Default for UseCookieOptions<T, E, D> {
|
||||||
#[cfg(not(feature = "ssr"))]
|
#[cfg(not(feature = "ssr"))]
|
||||||
None
|
None
|
||||||
}),
|
}),
|
||||||
ssr_set_cookie: Rc::new(|cookie: &Cookie| {
|
ssr_set_cookie: Arc::new(|cookie: &Cookie| {
|
||||||
#[cfg(feature = "ssr")]
|
#[cfg(feature = "ssr")]
|
||||||
{
|
{
|
||||||
#[cfg(feature = "actix")]
|
#[cfg(feature = "actix")]
|
||||||
|
@ -620,7 +619,7 @@ impl<T, E, D> Default for UseCookieOptions<T, E, D> {
|
||||||
|
|
||||||
let _ = cookie;
|
let _ = cookie;
|
||||||
}),
|
}),
|
||||||
on_error: Rc::new(|_| {
|
on_error: Arc::new(|_| {
|
||||||
error!("cookie (de-/)serialization error");
|
error!("cookie (de-/)serialization error");
|
||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
|
@ -628,7 +627,7 @@ impl<T, E, D> Default for UseCookieOptions<T, E, D> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn read_cookies_string(
|
fn read_cookies_string(
|
||||||
ssr_cookies_header_getter: Rc<dyn Fn() -> Option<String>>,
|
ssr_cookies_header_getter: Arc<dyn Fn() -> Option<String> + Send + Sync>,
|
||||||
) -> Option<String> {
|
) -> Option<String> {
|
||||||
let cookies;
|
let cookies;
|
||||||
|
|
||||||
|
@ -651,71 +650,80 @@ fn read_cookies_string(
|
||||||
cookies
|
cookies
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_expiration<T>(delay: Option<i64>, set_cookie: WriteSignal<Option<T>>) {
|
fn handle_expiration<T>(delay: Option<i64>, set_cookie: WriteSignal<Option<T>>)
|
||||||
|
where
|
||||||
|
T: Send + Sync + 'static,
|
||||||
|
{
|
||||||
if let Some(delay) = delay {
|
if let Some(delay) = delay {
|
||||||
#[cfg(not(feature = "ssr"))]
|
#[cfg(not(feature = "ssr"))]
|
||||||
{
|
{
|
||||||
use leptos::leptos_dom::helpers::TimeoutHandle;
|
use leptos::leptos_dom::helpers::TimeoutHandle;
|
||||||
use std::cell::Cell;
|
use std::sync::{atomic::AtomicI32, Mutex};
|
||||||
use std::cell::RefCell;
|
|
||||||
|
|
||||||
// The maximum value allowed on a timeout delay.
|
// The maximum value allowed on a timeout delay.
|
||||||
// Reference: https://developer.mozilla.org/en-US/docs/Web/API/setTimeout#maximum_delay_value
|
// Reference: https://developer.mozilla.org/en-US/docs/Web/API/setTimeout#maximum_delay_value
|
||||||
const MAX_TIMEOUT_DELAY: i64 = 2_147_483_647;
|
const MAX_TIMEOUT_DELAY: i64 = 2_147_483_647;
|
||||||
|
|
||||||
let timeout = Rc::new(Cell::new(None::<TimeoutHandle>));
|
let timeout = Arc::new(Mutex::new(None::<TimeoutHandle>));
|
||||||
let elapsed = Rc::new(Cell::new(0));
|
let elapsed = Arc::new(AtomicI32::new(0));
|
||||||
|
|
||||||
on_cleanup({
|
on_cleanup({
|
||||||
let timeout = Rc::clone(&timeout);
|
let timeout = Arc::clone(&timeout);
|
||||||
move || {
|
move || {
|
||||||
if let Some(timeout) = timeout.take() {
|
if let Some(timeout) = timeout.lock().unwrap().take() {
|
||||||
timeout.clear();
|
timeout.clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
let create_expiration_timeout = Rc::new(RefCell::new(None::<Box<dyn Fn()>>));
|
let create_expiration_timeout =
|
||||||
|
Arc::new(Mutex::new(None::<Box<dyn Fn() + Send + Sync>>));
|
||||||
|
|
||||||
create_expiration_timeout.replace(Some(Box::new({
|
*create_expiration_timeout.lock().unwrap() = Some(Box::new({
|
||||||
let timeout = Rc::clone(&timeout);
|
let timeout = Arc::clone(&timeout);
|
||||||
let elapsed = Rc::clone(&elapsed);
|
let elapsed = Arc::clone(&elapsed);
|
||||||
let create_expiration_timeout = Rc::clone(&create_expiration_timeout);
|
let create_expiration_timeout = Arc::clone(&create_expiration_timeout);
|
||||||
|
|
||||||
move || {
|
move || {
|
||||||
if let Some(timeout) = timeout.take() {
|
if let Some(timeout) = timeout.lock().unwrap().take() {
|
||||||
timeout.clear();
|
timeout.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
let time_remaining = delay - elapsed.get();
|
let time_remaining =
|
||||||
|
delay - elapsed.load(std::sync::atomic::Ordering::Relaxed) as i64;
|
||||||
let timeout_length = time_remaining.min(MAX_TIMEOUT_DELAY);
|
let timeout_length = time_remaining.min(MAX_TIMEOUT_DELAY);
|
||||||
|
|
||||||
let elapsed = Rc::clone(&elapsed);
|
let elapsed = Arc::clone(&elapsed);
|
||||||
let create_expiration_timeout = Rc::clone(&create_expiration_timeout);
|
let create_expiration_timeout = Arc::clone(&create_expiration_timeout);
|
||||||
|
|
||||||
timeout.set(
|
*timeout.lock().unwrap() = set_timeout_with_handle(
|
||||||
set_timeout_with_handle(
|
move || {
|
||||||
move || {
|
let elapsed = elapsed.fetch_add(
|
||||||
elapsed.set(elapsed.get() + timeout_length);
|
timeout_length as i32,
|
||||||
if elapsed.get() < delay {
|
std::sync::atomic::Ordering::Relaxed,
|
||||||
if let Some(create_expiration_timeout) =
|
) as i64
|
||||||
&*create_expiration_timeout.borrow()
|
+ timeout_length;
|
||||||
{
|
|
||||||
create_expiration_timeout();
|
if elapsed < delay {
|
||||||
}
|
if let Some(create_expiration_timeout) =
|
||||||
return;
|
create_expiration_timeout.lock().unwrap().as_ref()
|
||||||
|
{
|
||||||
|
create_expiration_timeout();
|
||||||
}
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
set_cookie.set(None);
|
set_cookie.set(None);
|
||||||
},
|
},
|
||||||
std::time::Duration::from_millis(timeout_length as u64),
|
std::time::Duration::from_millis(timeout_length as u64),
|
||||||
)
|
)
|
||||||
.ok(),
|
.ok();
|
||||||
);
|
|
||||||
}
|
}
|
||||||
})));
|
}));
|
||||||
|
|
||||||
if let Some(create_expiration_timeout) = &*create_expiration_timeout.borrow() {
|
if let Some(create_expiration_timeout) =
|
||||||
|
create_expiration_timeout.lock().unwrap().as_ref()
|
||||||
|
{
|
||||||
create_expiration_timeout();
|
create_expiration_timeout();
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -740,7 +748,7 @@ fn write_client_cookie(
|
||||||
same_site: Option<SameSite>,
|
same_site: Option<SameSite>,
|
||||||
secure: bool,
|
secure: bool,
|
||||||
http_only: bool,
|
http_only: bool,
|
||||||
ssr_cookies_header_getter: Rc<dyn Fn() -> Option<String>>,
|
ssr_cookies_header_getter: Arc<dyn Fn() -> Option<String> + Send + Sync>,
|
||||||
) {
|
) {
|
||||||
use wasm_bindgen::JsCast;
|
use wasm_bindgen::JsCast;
|
||||||
|
|
||||||
|
@ -776,7 +784,7 @@ fn update_client_cookie_jar(
|
||||||
same_site: Option<SameSite>,
|
same_site: Option<SameSite>,
|
||||||
secure: bool,
|
secure: bool,
|
||||||
http_only: bool,
|
http_only: bool,
|
||||||
ssr_cookies_header_getter: Rc<dyn Fn() -> Option<String>>,
|
ssr_cookies_header_getter: Arc<dyn Fn() -> Option<String> + Send + Sync>,
|
||||||
) {
|
) {
|
||||||
if let Some(new_jar) = load_and_parse_cookie_jar(ssr_cookies_header_getter) {
|
if let Some(new_jar) = load_and_parse_cookie_jar(ssr_cookies_header_getter) {
|
||||||
*jar = new_jar;
|
*jar = new_jar;
|
||||||
|
@ -864,7 +872,7 @@ fn write_server_cookie(
|
||||||
same_site: Option<SameSite>,
|
same_site: Option<SameSite>,
|
||||||
secure: bool,
|
secure: bool,
|
||||||
http_only: bool,
|
http_only: bool,
|
||||||
ssr_set_cookie: Rc<dyn Fn(&Cookie)>,
|
ssr_set_cookie: Arc<dyn Fn(&Cookie) + Send + Sync>,
|
||||||
) {
|
) {
|
||||||
if let Some(value) = value {
|
if let Some(value) = value {
|
||||||
let cookie: Cookie = build_cookie_from_options(
|
let cookie: Cookie = build_cookie_from_options(
|
||||||
|
@ -882,7 +890,7 @@ fn write_server_cookie(
|
||||||
}
|
}
|
||||||
|
|
||||||
fn load_and_parse_cookie_jar(
|
fn load_and_parse_cookie_jar(
|
||||||
ssr_cookies_header_getter: Rc<dyn Fn() -> Option<String>>,
|
ssr_cookies_header_getter: Arc<dyn Fn() -> Option<String> + Send + Sync>,
|
||||||
) -> Option<CookieJar> {
|
) -> Option<CookieJar> {
|
||||||
read_cookies_string(ssr_cookies_header_getter).map(|cookies| {
|
read_cookies_string(ssr_cookies_header_getter).map(|cookies| {
|
||||||
let mut jar = CookieJar::new();
|
let mut jar = CookieJar::new();
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
use crate::core::MaybeRwSignal;
|
use crate::core::MaybeRwSignal;
|
||||||
use default_struct_builder::DefaultBuilder;
|
use default_struct_builder::DefaultBuilder;
|
||||||
use leptos::prelude::wrappers::read::Signal;
|
|
||||||
use leptos::prelude::*;
|
use leptos::prelude::*;
|
||||||
|
|
||||||
/// Cycle through a list of items.
|
/// Cycle through a list of items.
|
||||||
|
@ -156,7 +155,7 @@ where
|
||||||
let _ = {
|
let _ = {
|
||||||
let set = set.clone();
|
let set = set.clone();
|
||||||
|
|
||||||
leptos::watch(move || list.get(), move |_, _, _| set(index.get()), false)
|
watch(move || list.get(), move |_, _, _| set(index.get()), false)
|
||||||
};
|
};
|
||||||
|
|
||||||
UseCycleListReturn {
|
UseCycleListReturn {
|
||||||
|
@ -174,7 +173,7 @@ where
|
||||||
#[derive(DefaultBuilder)]
|
#[derive(DefaultBuilder)]
|
||||||
pub struct UseCycleListOptions<T>
|
pub struct UseCycleListOptions<T>
|
||||||
where
|
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
|
/// The initial value of the state. Can be a Signal. If none is provided the first entry
|
||||||
/// of the list will be used.
|
/// of the list will be used.
|
||||||
|
@ -192,7 +191,7 @@ where
|
||||||
|
|
||||||
impl<T> Default for UseCycleListOptions<T>
|
impl<T> Default for UseCycleListOptions<T>
|
||||||
where
|
where
|
||||||
T: Clone + PartialEq + 'static,
|
T: Clone + PartialEq + Send + Sync + 'static,
|
||||||
{
|
{
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
|
@ -206,7 +205,7 @@ where
|
||||||
/// Return type of [`use_cycle_list`].
|
/// Return type of [`use_cycle_list`].
|
||||||
pub struct UseCycleListReturn<T, SetFn, NextFn, PrevFn, ShiftFn>
|
pub struct UseCycleListReturn<T, SetFn, NextFn, PrevFn, ShiftFn>
|
||||||
where
|
where
|
||||||
T: Clone + PartialEq + 'static,
|
T: Clone + PartialEq + Send + Sync + 'static,
|
||||||
SetFn: Fn(usize) -> T + Clone,
|
SetFn: Fn(usize) -> T + Clone,
|
||||||
NextFn: Fn() + Clone,
|
NextFn: Fn() + Clone,
|
||||||
PrevFn: Fn() + Clone,
|
PrevFn: Fn() + Clone,
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
use cfg_if::cfg_if;
|
use cfg_if::cfg_if;
|
||||||
use leptos::prelude::wrappers::read::Signal;
|
use leptos::prelude::wrappers::read::Signal;
|
||||||
|
use send_wrapper::SendWrapper;
|
||||||
|
|
||||||
/// Reactive [DeviceOrientationEvent](https://developer.mozilla.org/en-US/docs/Web/API/DeviceOrientationEvent).
|
/// Reactive [DeviceOrientationEvent](https://developer.mozilla.org/en-US/docs/Web/API/DeviceOrientationEvent).
|
||||||
/// Provide web developers with information from the physical orientation of
|
/// Provide web developers with information from the physical orientation of
|
||||||
|
@ -36,10 +37,10 @@ use leptos::prelude::wrappers::read::Signal;
|
||||||
pub fn use_device_orientation() -> UseDeviceOrientationReturn {
|
pub fn use_device_orientation() -> UseDeviceOrientationReturn {
|
||||||
cfg_if! { if #[cfg(feature = "ssr")] {
|
cfg_if! { if #[cfg(feature = "ssr")] {
|
||||||
let is_supported = Signal::derive(|| false);
|
let is_supported = Signal::derive(|| false);
|
||||||
let absolute = || false;
|
let absolute = Signal::derive(|| false);
|
||||||
let alpha = || None;
|
let alpha = Signal::derive(|| None);
|
||||||
let beta = || None;
|
let beta = Signal::derive(|| None);
|
||||||
let gamma = || None;
|
let gamma = Signal::derive(|| None);
|
||||||
} else {
|
} else {
|
||||||
use leptos::prelude::*;
|
use leptos::prelude::*;
|
||||||
use crate::{use_event_listener_with_options, UseEventListenerOptions, use_supported, js};
|
use crate::{use_event_listener_with_options, UseEventListenerOptions, use_supported, js};
|
||||||
|
@ -67,7 +68,10 @@ pub fn use_device_orientation() -> UseDeviceOrientationReturn {
|
||||||
.once(false),
|
.once(false),
|
||||||
);
|
);
|
||||||
|
|
||||||
on_cleanup(cleanup);
|
on_cleanup({
|
||||||
|
let cleanup = SendWrapper::new(cleanup);
|
||||||
|
move || cleanup()
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,6 @@ use cfg_if::cfg_if;
|
||||||
use default_struct_builder::DefaultBuilder;
|
use default_struct_builder::DefaultBuilder;
|
||||||
use leptos::prelude::wrappers::read::Signal;
|
use leptos::prelude::wrappers::read::Signal;
|
||||||
use leptos::prelude::*;
|
use leptos::prelude::*;
|
||||||
use send_wrapper::SendWrapper;
|
|
||||||
use wasm_bindgen::{JsCast, JsValue};
|
use wasm_bindgen::{JsCast, JsValue};
|
||||||
|
|
||||||
/// Reactive [`mediaDevices.getDisplayMedia`](https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/getDisplayMedia) streaming.
|
/// 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 (enabled, set_enabled) = enabled.into_signal();
|
||||||
|
|
||||||
let (stream, set_stream) =
|
let (stream, set_stream) = signal_local(None::<Result<web_sys::MediaStream, JsValue>>);
|
||||||
signal(None::<Result<SendWrapper<web_sys::MediaStream>, SendWrapper<JsValue>>>);
|
|
||||||
|
|
||||||
let _start = move || async move {
|
let _start = move || async move {
|
||||||
cfg_if! { if #[cfg(not(feature = "ssr"))] {
|
cfg_if! { if #[cfg(not(feature = "ssr"))] {
|
||||||
|
@ -65,10 +63,7 @@ pub fn use_display_media_with_options(
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let stream = create_media(audio)
|
let stream = create_media(audio).await;
|
||||||
.await
|
|
||||||
.map(SendWrapper::new)
|
|
||||||
.map_err(SendWrapper::new);
|
|
||||||
|
|
||||||
set_stream.update(|s| *s = Some(stream));
|
set_stream.update(|s| *s = Some(stream));
|
||||||
} else {
|
} else {
|
||||||
|
@ -181,7 +176,7 @@ where
|
||||||
/// Initially this is `None` until `start` resolved successfully.
|
/// 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,
|
/// In case the stream couldn't be started, for example because the user didn't grant permission,
|
||||||
/// this has the value `Some(Err(...))`.
|
/// this has the value `Some(Err(...))`.
|
||||||
pub stream: Signal<Option<Result<SendWrapper<web_sys::MediaStream>, SendWrapper<JsValue>>>>,
|
pub stream: Signal<Option<Result<web_sys::MediaStream, JsValue>>, LocalStorage>,
|
||||||
|
|
||||||
/// Starts the screen streaming. Triggers the ask for permission if not already granted.
|
/// Starts the screen streaming. Triggers the ask for permission if not already granted.
|
||||||
pub start: StartFn,
|
pub start: StartFn,
|
||||||
|
|
|
@ -6,7 +6,7 @@ use leptos::prelude::diagnostics::SpecialNonReactiveZone;
|
||||||
use leptos::prelude::wrappers::read::Signal;
|
use leptos::prelude::wrappers::read::Signal;
|
||||||
use leptos::prelude::*;
|
use leptos::prelude::*;
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
use std::rc::Rc;
|
use std::sync::Arc;
|
||||||
use wasm_bindgen::JsCast;
|
use wasm_bindgen::JsCast;
|
||||||
use web_sys::PointerEvent;
|
use web_sys::PointerEvent;
|
||||||
|
|
||||||
|
@ -92,11 +92,11 @@ where
|
||||||
let target = target.into();
|
let target = target.into();
|
||||||
|
|
||||||
let dragging_handle = if let Some(handle) = handle {
|
let dragging_handle = if let Some(handle) = handle {
|
||||||
let handle = (handle).into();
|
let handle: ElementMaybeSignal<_, _> = handle.into();
|
||||||
Signal::derive(move || handle.get().map(|handle| handle.into()))
|
Signal::derive_local(move || handle.get().map(|handle| handle.into()))
|
||||||
} else {
|
} else {
|
||||||
let target = target.clone();
|
let target = target.clone();
|
||||||
Signal::derive(move || target.get().map(|target| target.into()))
|
Signal::derive_local(move || target.get().map(|target| target.into()))
|
||||||
};
|
};
|
||||||
|
|
||||||
let (position, set_position) = initial_value.into_signal();
|
let (position, set_position) = initial_value.into_signal();
|
||||||
|
@ -280,13 +280,13 @@ where
|
||||||
initial_value: MaybeRwSignal<Position>,
|
initial_value: MaybeRwSignal<Position>,
|
||||||
|
|
||||||
/// Callback when the dragging starts. Return `false` to prevent dragging.
|
/// Callback when the dragging starts. Return `false` to prevent dragging.
|
||||||
on_start: Rc<dyn Fn(UseDraggableCallbackArgs) -> bool>,
|
on_start: Arc<dyn Fn(UseDraggableCallbackArgs) -> bool + Send + Sync>,
|
||||||
|
|
||||||
/// Callback during dragging.
|
/// Callback during dragging.
|
||||||
on_move: Rc<dyn Fn(UseDraggableCallbackArgs)>,
|
on_move: Arc<dyn Fn(UseDraggableCallbackArgs) + Send + Sync>,
|
||||||
|
|
||||||
/// Callback when dragging end.
|
/// Callback when dragging end.
|
||||||
on_end: Rc<dyn Fn(UseDraggableCallbackArgs)>,
|
on_end: Arc<dyn Fn(UseDraggableCallbackArgs) + Send + Sync>,
|
||||||
|
|
||||||
#[builder(skip)]
|
#[builder(skip)]
|
||||||
_marker1: PhantomData<DragT>,
|
_marker1: PhantomData<DragT>,
|
||||||
|
@ -306,9 +306,9 @@ impl Default
|
||||||
handle: None,
|
handle: None,
|
||||||
pointer_types: vec![PointerType::Mouse, PointerType::Touch, PointerType::Pen],
|
pointer_types: vec![PointerType::Mouse, PointerType::Touch, PointerType::Pen],
|
||||||
initial_value: MaybeRwSignal::default(),
|
initial_value: MaybeRwSignal::default(),
|
||||||
on_start: Rc::new(|_| true),
|
on_start: Arc::new(|_| true),
|
||||||
on_move: Rc::new(|_| {}),
|
on_move: Arc::new(|_| {}),
|
||||||
on_end: Rc::new(|_| {}),
|
on_end: Arc::new(|_| {}),
|
||||||
_marker1: PhantomData,
|
_marker1: PhantomData,
|
||||||
_marker2: PhantomData,
|
_marker2: PhantomData,
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,7 @@ use default_struct_builder::DefaultBuilder;
|
||||||
use leptos::prelude::wrappers::read::Signal;
|
use leptos::prelude::wrappers::read::Signal;
|
||||||
use leptos::prelude::*;
|
use leptos::prelude::*;
|
||||||
use std::fmt::{Debug, Formatter};
|
use std::fmt::{Debug, Formatter};
|
||||||
use std::rc::Rc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
cfg_if! { if #[cfg(not(feature = "ssr"))] {
|
cfg_if! { if #[cfg(not(feature = "ssr"))] {
|
||||||
use crate::use_event_listener;
|
use crate::use_event_listener;
|
||||||
|
@ -73,7 +73,7 @@ where
|
||||||
T: Into<web_sys::EventTarget> + Clone + 'static,
|
T: Into<web_sys::EventTarget> + Clone + 'static,
|
||||||
{
|
{
|
||||||
let (is_over_drop_zone, set_over_drop_zone) = signal(false);
|
let (is_over_drop_zone, set_over_drop_zone) = signal(false);
|
||||||
let (files, set_files) = signal(Vec::<web_sys::File>::new());
|
let (files, set_files) = signal_local(Vec::<web_sys::File>::new());
|
||||||
|
|
||||||
#[cfg(not(feature = "ssr"))]
|
#[cfg(not(feature = "ssr"))]
|
||||||
{
|
{
|
||||||
|
@ -89,7 +89,7 @@ where
|
||||||
|
|
||||||
let update_files = move |event: &web_sys::DragEvent| {
|
let update_files = move |event: &web_sys::DragEvent| {
|
||||||
if let Some(data_transfer) = event.data_transfer() {
|
if let Some(data_transfer) = event.data_transfer() {
|
||||||
let files: Vec<web_sys::File> = data_transfer
|
let files: Vec<_> = data_transfer
|
||||||
.files()
|
.files()
|
||||||
.map(|f| js_sys::Array::from(&f).to_vec())
|
.map(|f| js_sys::Array::from(&f).to_vec())
|
||||||
.unwrap_or_default()
|
.unwrap_or_default()
|
||||||
|
@ -112,7 +112,7 @@ where
|
||||||
let _z = SpecialNonReactiveZone::enter();
|
let _z = SpecialNonReactiveZone::enter();
|
||||||
|
|
||||||
on_enter(UseDropZoneEvent {
|
on_enter(UseDropZoneEvent {
|
||||||
files: files.get_untracked(),
|
files: files.get_untracked().into_iter().collect(),
|
||||||
event,
|
event,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -125,7 +125,7 @@ where
|
||||||
let _z = SpecialNonReactiveZone::enter();
|
let _z = SpecialNonReactiveZone::enter();
|
||||||
|
|
||||||
on_over(UseDropZoneEvent {
|
on_over(UseDropZoneEvent {
|
||||||
files: files.get_untracked(),
|
files: files.get_untracked().into_iter().collect(),
|
||||||
event,
|
event,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -143,7 +143,7 @@ where
|
||||||
let _z = SpecialNonReactiveZone::enter();
|
let _z = SpecialNonReactiveZone::enter();
|
||||||
|
|
||||||
on_leave(UseDropZoneEvent {
|
on_leave(UseDropZoneEvent {
|
||||||
files: files.get_untracked(),
|
files: files.get_untracked().into_iter().collect(),
|
||||||
event,
|
event,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -159,7 +159,7 @@ where
|
||||||
let _z = SpecialNonReactiveZone::enter();
|
let _z = SpecialNonReactiveZone::enter();
|
||||||
|
|
||||||
on_drop(UseDropZoneEvent {
|
on_drop(UseDropZoneEvent {
|
||||||
files: files.get_untracked(),
|
files: files.get_untracked().into_iter().collect(),
|
||||||
event,
|
event,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -176,22 +176,22 @@ where
|
||||||
#[cfg_attr(feature = "ssr", allow(dead_code))]
|
#[cfg_attr(feature = "ssr", allow(dead_code))]
|
||||||
pub struct UseDropZoneOptions {
|
pub struct UseDropZoneOptions {
|
||||||
/// Event handler for the [`drop`](https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/drop_event) event
|
/// Event handler for the [`drop`](https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/drop_event) event
|
||||||
on_drop: Rc<dyn Fn(UseDropZoneEvent)>,
|
on_drop: Arc<dyn Fn(UseDropZoneEvent) + Send + Sync>,
|
||||||
/// Event handler for the [`dragenter`](https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/dragenter_event) event
|
/// Event handler for the [`dragenter`](https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/dragenter_event) event
|
||||||
on_enter: Rc<dyn Fn(UseDropZoneEvent)>,
|
on_enter: Arc<dyn Fn(UseDropZoneEvent) + Send + Sync>,
|
||||||
/// Event handler for the [`dragleave`](https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/dragleave_event) event
|
/// Event handler for the [`dragleave`](https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/dragleave_event) event
|
||||||
on_leave: Rc<dyn Fn(UseDropZoneEvent)>,
|
on_leave: Arc<dyn Fn(UseDropZoneEvent) + Send + Sync>,
|
||||||
/// Event handler for the [`dragover`](https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/dragover_event) event
|
/// Event handler for the [`dragover`](https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/dragover_event) event
|
||||||
on_over: Rc<dyn Fn(UseDropZoneEvent)>,
|
on_over: Arc<dyn Fn(UseDropZoneEvent) + Send + Sync>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for UseDropZoneOptions {
|
impl Default for UseDropZoneOptions {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
on_drop: Rc::new(|_| {}),
|
on_drop: Arc::new(|_| {}),
|
||||||
on_enter: Rc::new(|_| {}),
|
on_enter: Arc::new(|_| {}),
|
||||||
on_leave: Rc::new(|_| {}),
|
on_leave: Arc::new(|_| {}),
|
||||||
on_over: Rc::new(|_| {}),
|
on_over: Arc::new(|_| {}),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -214,7 +214,7 @@ pub struct UseDropZoneEvent {
|
||||||
/// Return type of [`use_drop_zone`].
|
/// Return type of [`use_drop_zone`].
|
||||||
pub struct UseDropZoneReturn {
|
pub struct UseDropZoneReturn {
|
||||||
/// Files being handled
|
/// Files being handled
|
||||||
pub files: Signal<Vec<web_sys::File>>,
|
pub files: Signal<Vec<web_sys::File>, LocalStorage>,
|
||||||
/// Whether the files (dragged by the pointer) are over the drop zone
|
/// Whether the files (dragged by the pointer) are over the drop zone
|
||||||
pub is_over_drop_zone: Signal<bool>,
|
pub is_over_drop_zone: Signal<bool>,
|
||||||
}
|
}
|
||||||
|
|
|
@ -188,8 +188,10 @@ where
|
||||||
cleanup_prev_element();
|
cleanup_prev_element();
|
||||||
};
|
};
|
||||||
|
|
||||||
let cleanup_stop = SendWrapper::new(stop.clone());
|
on_cleanup({
|
||||||
on_cleanup(move || cleanup_stop());
|
let stop = SendWrapper::new(stop.clone());
|
||||||
|
move || stop()
|
||||||
|
});
|
||||||
|
|
||||||
stop
|
stop
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,9 +4,8 @@ use codee::Decoder;
|
||||||
use default_struct_builder::DefaultBuilder;
|
use default_struct_builder::DefaultBuilder;
|
||||||
use leptos::prelude::diagnostics::SpecialNonReactiveZone;
|
use leptos::prelude::diagnostics::SpecialNonReactiveZone;
|
||||||
use leptos::prelude::*;
|
use leptos::prelude::*;
|
||||||
use send_wrapper::SendWrapper;
|
|
||||||
use std::cell::Cell;
|
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
|
use std::sync::atomic::{AtomicBool, AtomicU32};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
@ -143,14 +142,14 @@ where
|
||||||
|
|
||||||
let url = url.to_owned();
|
let url = url.to_owned();
|
||||||
|
|
||||||
let (event, set_event) = signal(None::<SendWrapper<web_sys::Event>>);
|
let (event, set_event) = signal_local(None::<web_sys::Event>);
|
||||||
let (data, set_data) = signal(None::<T>);
|
let (data, set_data) = signal(None::<T>);
|
||||||
let (ready_state, set_ready_state) = signal(ConnectionReadyState::Closed);
|
let (ready_state, set_ready_state) = signal(ConnectionReadyState::Closed);
|
||||||
let (event_source, set_event_source) = signal(None::<SendWrapper<web_sys::EventSource>>);
|
let (event_source, set_event_source) = signal_local(None::<web_sys::EventSource>);
|
||||||
let (error, set_error) = signal(None::<UseEventSourceError<C::Error>>);
|
let (error, set_error) = signal_local(None::<UseEventSourceError<C::Error>>);
|
||||||
|
|
||||||
let explicitly_closed = Arc::new(Cell::new(false));
|
let explicitly_closed = Arc::new(AtomicBool::new(false));
|
||||||
let retried = Arc::new(Cell::new(0));
|
let retried = Arc::new(AtomicU32::new(0));
|
||||||
|
|
||||||
let set_data_from_string = move |data_string: Option<String>| {
|
let set_data_from_string = move |data_string: Option<String>| {
|
||||||
if let Some(data_string) = data_string {
|
if let Some(data_string) = data_string {
|
||||||
|
@ -169,7 +168,7 @@ where
|
||||||
event_source.close();
|
event_source.close();
|
||||||
set_event_source.set(None);
|
set_event_source.set(None);
|
||||||
set_ready_state.set(ConnectionReadyState::Closed);
|
set_ready_state.set(ConnectionReadyState::Closed);
|
||||||
explicitly_closed.set(true);
|
explicitly_closed.store(true, std::sync::atomic::Ordering::Relaxed);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -183,7 +182,7 @@ where
|
||||||
move || {
|
move || {
|
||||||
use wasm_bindgen::prelude::*;
|
use wasm_bindgen::prelude::*;
|
||||||
|
|
||||||
if explicitly_closed.get() {
|
if explicitly_closed.load(std::sync::atomic::Ordering::Relaxed) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -195,7 +194,7 @@ where
|
||||||
|
|
||||||
set_ready_state.set(ConnectionReadyState::Connecting);
|
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| {
|
let on_open = Closure::wrap(Box::new(move |_: web_sys::Event| {
|
||||||
set_ready_state.set(ConnectionReadyState::Open);
|
set_ready_state.set(ConnectionReadyState::Open);
|
||||||
|
@ -212,19 +211,20 @@ where
|
||||||
|
|
||||||
move |e: web_sys::Event| {
|
move |e: web_sys::Event| {
|
||||||
set_ready_state.set(ConnectionReadyState::Closed);
|
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
|
// only reconnect if EventSource isn't reconnecting by itself
|
||||||
// this is the case when the connection is closed (readyState is 2)
|
// this is the case when the connection is closed (readyState is 2)
|
||||||
if es.ready_state() == 2
|
if es.ready_state() == 2
|
||||||
&& !explicitly_closed.get()
|
&& !explicitly_closed.load(std::sync::atomic::Ordering::Relaxed)
|
||||||
&& matches!(reconnect_limit, ReconnectLimit::Limited(_))
|
&& matches!(reconnect_limit, ReconnectLimit::Limited(_))
|
||||||
{
|
{
|
||||||
es.close();
|
es.close();
|
||||||
|
|
||||||
retried.set(retried.get() + 1);
|
let retried_value =
|
||||||
|
retried.fetch_add(1, std::sync::atomic::Ordering::Relaxed) + 1;
|
||||||
|
|
||||||
if reconnect_limit.is_exceeded_by(retried.get()) {
|
if reconnect_limit.is_exceeded_by(retried_value as u64) {
|
||||||
set_timeout(
|
set_timeout(
|
||||||
move || {
|
move || {
|
||||||
if let Some(init) = init.get_value() {
|
if let Some(init) = init.get_value() {
|
||||||
|
@ -254,7 +254,7 @@ where
|
||||||
for event_name in named_events.clone() {
|
for event_name in named_events.clone() {
|
||||||
let _ = use_event_listener(
|
let _ = use_event_listener(
|
||||||
es.clone(),
|
es.clone(),
|
||||||
leptos::ev::Custom::<ev::Event>::new(event_name),
|
leptos::ev::Custom::<leptos::ev::Event>::new(event_name),
|
||||||
move |e| {
|
move |e| {
|
||||||
set_event.set(Some(e.clone()));
|
set_event.set(Some(e.clone()));
|
||||||
let data_string = js!(e["data"]).ok().and_then(|d| d.as_string());
|
let data_string = js!(e["data"]).ok().and_then(|d| d.as_string());
|
||||||
|
@ -276,8 +276,8 @@ where
|
||||||
|
|
||||||
move || {
|
move || {
|
||||||
close();
|
close();
|
||||||
explicitly_closed.set(false);
|
explicitly_closed.store(false, std::sync::atomic::Ordering::Relaxed);
|
||||||
retried.set(0);
|
retried.store(0, std::sync::atomic::Ordering::Relaxed);
|
||||||
if let Some(init) = init.get_value() {
|
if let Some(init) = init.get_value() {
|
||||||
init();
|
init();
|
||||||
}
|
}
|
||||||
|
@ -321,7 +321,7 @@ where
|
||||||
reconnect_interval: u64,
|
reconnect_interval: u64,
|
||||||
|
|
||||||
/// On maximum retry times reached.
|
/// On maximum retry times reached.
|
||||||
on_failed: Arc<dyn Fn()>,
|
on_failed: Arc<dyn Fn() + Send + Sync>,
|
||||||
|
|
||||||
/// If `true` the `EventSource` connection will immediately be opened when calling this function.
|
/// If `true` the `EventSource` connection will immediately be opened when calling this function.
|
||||||
/// If `false` you have to manually call the `open` function.
|
/// If `false` you have to manually call the `open` function.
|
||||||
|
@ -367,10 +367,10 @@ where
|
||||||
pub ready_state: Signal<ConnectionReadyState>,
|
pub ready_state: Signal<ConnectionReadyState>,
|
||||||
|
|
||||||
/// The latest named event
|
/// The latest named event
|
||||||
pub event: Signal<Option<SendWrapper<web_sys::Event>>>,
|
pub event: Signal<Option<web_sys::Event>, LocalStorage>,
|
||||||
|
|
||||||
/// The current error
|
/// The current error
|
||||||
pub error: Signal<Option<UseEventSourceError<Err>>>,
|
pub error: Signal<Option<UseEventSourceError<Err>>, LocalStorage>,
|
||||||
|
|
||||||
/// (Re-)Opens the `EventSource` connection
|
/// (Re-)Opens the `EventSource` connection
|
||||||
/// If the current one is active, will close it before opening a new one.
|
/// If the current one is active, will close it before opening a new one.
|
||||||
|
@ -380,13 +380,13 @@ where
|
||||||
pub close: CloseFn,
|
pub close: CloseFn,
|
||||||
|
|
||||||
/// The `EventSource` instance
|
/// The `EventSource` instance
|
||||||
pub event_source: Signal<Option<SendWrapper<web_sys::EventSource>>>,
|
pub event_source: Signal<Option<web_sys::EventSource>, LocalStorage>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Error, Debug)]
|
#[derive(Error, Debug)]
|
||||||
pub enum UseEventSourceError<Err> {
|
pub enum UseEventSourceError<Err> {
|
||||||
#[error("Error event: {0:?}")]
|
#[error("Error event: {0:?}")]
|
||||||
Event(SendWrapper<web_sys::Event>),
|
Event(web_sys::Event),
|
||||||
|
|
||||||
#[error("Error decoding value")]
|
#[error("Error decoding value")]
|
||||||
Deserialize(Err),
|
Deserialize(Err),
|
||||||
|
|
|
@ -2,7 +2,6 @@ use cfg_if::cfg_if;
|
||||||
use default_struct_builder::DefaultBuilder;
|
use default_struct_builder::DefaultBuilder;
|
||||||
use leptos::prelude::wrappers::read::Signal;
|
use leptos::prelude::wrappers::read::Signal;
|
||||||
use leptos::prelude::*;
|
use leptos::prelude::*;
|
||||||
use send_wrapper::SendWrapper;
|
|
||||||
|
|
||||||
/// Reactive [Geolocation API](https://developer.mozilla.org/en-US/docs/Web/API/Geolocation_API).
|
/// 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,
|
/// 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,
|
options: UseGeolocationOptions,
|
||||||
) -> UseGeolocationReturn<impl Fn() + Clone, impl Fn() + Clone> {
|
) -> UseGeolocationReturn<impl Fn() + Clone, impl Fn() + Clone> {
|
||||||
let (located_at, set_located_at) = signal(None::<f64>);
|
let (located_at, set_located_at) = signal(None::<f64>);
|
||||||
let (error, set_error) = signal(None::<SendWrapper<web_sys::PositionError>>);
|
let (error, set_error) = signal_local(None::<web_sys::PositionError>);
|
||||||
let (coords, set_coords) = signal(None::<SendWrapper<web_sys::Coordinates>>);
|
let (coords, set_coords) = signal_local(None::<web_sys::Coordinates>);
|
||||||
|
|
||||||
cfg_if! { if #[cfg(feature = "ssr")] {
|
cfg_if! { if #[cfg(feature = "ssr")] {
|
||||||
let resume = || ();
|
let resume = || ();
|
||||||
|
@ -62,12 +61,12 @@ pub fn use_geolocation_with_options(
|
||||||
|
|
||||||
let update_position = move |position: web_sys::Position| {
|
let update_position = move |position: web_sys::Position| {
|
||||||
set_located_at.set(Some(position.timestamp()));
|
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);
|
set_error.set(None);
|
||||||
};
|
};
|
||||||
|
|
||||||
let on_error = move |err: web_sys::PositionError| {
|
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::<i32>));
|
let watch_handle = Arc::new(Mutex::new(None::<i32>));
|
||||||
|
@ -203,13 +202,13 @@ where
|
||||||
{
|
{
|
||||||
/// The coordinates of the current device like latitude and longitude.
|
/// The coordinates of the current device like latitude and longitude.
|
||||||
/// See [`GeolocationCoordinates`](https://developer.mozilla.org/en-US/docs/Web/API/GeolocationCoordinates)..
|
/// See [`GeolocationCoordinates`](https://developer.mozilla.org/en-US/docs/Web/API/GeolocationCoordinates)..
|
||||||
pub coords: Signal<Option<SendWrapper<web_sys::Coordinates>>>,
|
pub coords: Signal<Option<web_sys::Coordinates>, LocalStorage>,
|
||||||
|
|
||||||
/// The timestamp of the current coordinates.
|
/// The timestamp of the current coordinates.
|
||||||
pub located_at: Signal<Option<f64>>,
|
pub located_at: Signal<Option<f64>>,
|
||||||
|
|
||||||
/// The last error received from `navigator.geolocation`.
|
/// The last error received from `navigator.geolocation`.
|
||||||
pub error: Signal<Option<SendWrapper<web_sys::PositionError>>>,
|
pub error: Signal<Option<web_sys::PositionError>, LocalStorage>,
|
||||||
|
|
||||||
/// Resume the geolocation watch.
|
/// Resume the geolocation watch.
|
||||||
pub resume: ResumeFn,
|
pub resume: ResumeFn,
|
||||||
|
|
|
@ -10,7 +10,7 @@ use leptos::prelude::diagnostics::SpecialNonReactiveZone;
|
||||||
use leptos::prelude::wrappers::read::Signal;
|
use leptos::prelude::wrappers::read::Signal;
|
||||||
use leptos::prelude::*;
|
use leptos::prelude::*;
|
||||||
use std::future::Future;
|
use std::future::Future;
|
||||||
use std::rc::Rc;
|
use std::sync::Arc;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
use wasm_bindgen::JsCast;
|
use wasm_bindgen::JsCast;
|
||||||
|
|
||||||
|
@ -55,7 +55,7 @@ pub fn use_infinite_scroll<El, T, LFn, LFut>(el: El, on_load_more: LFn) -> Signa
|
||||||
where
|
where
|
||||||
El: Into<ElementMaybeSignal<T, web_sys::Element>> + Clone + 'static,
|
El: Into<ElementMaybeSignal<T, web_sys::Element>> + Clone + 'static,
|
||||||
T: Into<web_sys::Element> + Clone + 'static,
|
T: Into<web_sys::Element> + Clone + 'static,
|
||||||
LFn: Fn(ScrollState) -> LFut + 'static,
|
LFn: Fn(ScrollState) -> LFut + Send + Sync + 'static,
|
||||||
LFut: Future<Output = ()>,
|
LFut: Future<Output = ()>,
|
||||||
{
|
{
|
||||||
use_infinite_scroll_with_options(el, on_load_more, UseInfiniteScrollOptions::default())
|
use_infinite_scroll_with_options(el, on_load_more, UseInfiniteScrollOptions::default())
|
||||||
|
@ -70,7 +70,7 @@ pub fn use_infinite_scroll_with_options<El, T, LFn, LFut>(
|
||||||
where
|
where
|
||||||
El: Into<ElementMaybeSignal<T, web_sys::Element>> + Clone + 'static,
|
El: Into<ElementMaybeSignal<T, web_sys::Element>> + Clone + 'static,
|
||||||
T: Into<web_sys::Element> + Clone + 'static,
|
T: Into<web_sys::Element> + Clone + 'static,
|
||||||
LFn: Fn(ScrollState) -> LFut + 'static,
|
LFn: Fn(ScrollState) -> LFut + Send + Sync + 'static,
|
||||||
LFut: Future<Output = ()>,
|
LFut: Future<Output = ()>,
|
||||||
{
|
{
|
||||||
let UseInfiniteScrollOptions {
|
let UseInfiniteScrollOptions {
|
||||||
|
@ -110,7 +110,7 @@ where
|
||||||
let (is_loading, set_loading) = signal(false);
|
let (is_loading, set_loading) = signal(false);
|
||||||
|
|
||||||
let el = el.into();
|
let el = el.into();
|
||||||
let observed_element = Signal::derive(move || {
|
let observed_element = Signal::derive_local(move || {
|
||||||
let el = el.get();
|
let el = el.get();
|
||||||
|
|
||||||
el.map(|el| {
|
el.map(|el| {
|
||||||
|
@ -128,9 +128,9 @@ where
|
||||||
|
|
||||||
let is_element_visible = use_element_visibility(observed_element);
|
let is_element_visible = use_element_visibility(observed_element);
|
||||||
|
|
||||||
let check_and_load = StoredValue::new(None::<Rc<dyn Fn()>>);
|
let check_and_load = StoredValue::new(None::<Arc<dyn Fn() + Send + Sync>>);
|
||||||
|
|
||||||
check_and_load.set_value(Some(Rc::new({
|
check_and_load.set_value(Some(Arc::new({
|
||||||
let measure = measure.clone();
|
let measure = measure.clone();
|
||||||
|
|
||||||
move || {
|
move || {
|
||||||
|
@ -215,7 +215,7 @@ where
|
||||||
#[derive(DefaultBuilder)]
|
#[derive(DefaultBuilder)]
|
||||||
pub struct UseInfiniteScrollOptions {
|
pub struct UseInfiniteScrollOptions {
|
||||||
/// Callback when scrolling is happening.
|
/// Callback when scrolling is happening.
|
||||||
on_scroll: Rc<dyn Fn(web_sys::Event)>,
|
on_scroll: Arc<dyn Fn(web_sys::Event) + Send + Sync>,
|
||||||
|
|
||||||
/// Options passed to the `addEventListener("scroll", ...)` call
|
/// Options passed to the `addEventListener("scroll", ...)` call
|
||||||
event_listener_options: UseEventListenerOptions,
|
event_listener_options: UseEventListenerOptions,
|
||||||
|
@ -233,7 +233,7 @@ pub struct UseInfiniteScrollOptions {
|
||||||
impl Default for UseInfiniteScrollOptions {
|
impl Default for UseInfiniteScrollOptions {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
on_scroll: Rc::new(|_| {}),
|
on_scroll: Arc::new(|_| {}),
|
||||||
event_listener_options: Default::default(),
|
event_listener_options: Default::default(),
|
||||||
distance: 0.0,
|
distance: 0.0,
|
||||||
direction: Direction::Bottom,
|
direction: Direction::Bottom,
|
||||||
|
|
|
@ -3,12 +3,14 @@ use cfg_if::cfg_if;
|
||||||
use default_struct_builder::DefaultBuilder;
|
use default_struct_builder::DefaultBuilder;
|
||||||
use leptos::prelude::wrappers::read::Signal;
|
use leptos::prelude::wrappers::read::Signal;
|
||||||
use leptos::prelude::*;
|
use leptos::prelude::*;
|
||||||
|
use send_wrapper::SendWrapper;
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
|
|
||||||
cfg_if! { if #[cfg(not(feature = "ssr"))] {
|
cfg_if! { if #[cfg(not(feature = "ssr"))] {
|
||||||
use crate::{watch_with_options, WatchOptions};
|
use crate::{watch_with_options, WatchOptions};
|
||||||
use std::cell::RefCell;
|
// use std::cell::RefCell;
|
||||||
use std::rc::Rc;
|
// use std::rc::Rc;
|
||||||
|
use std::sync::{Arc, Mutex};
|
||||||
use wasm_bindgen::prelude::*;
|
use wasm_bindgen::prelude::*;
|
||||||
}}
|
}}
|
||||||
|
|
||||||
|
@ -116,14 +118,14 @@ where
|
||||||
)
|
)
|
||||||
.into_js_value();
|
.into_js_value();
|
||||||
|
|
||||||
let observer: Rc<RefCell<Option<web_sys::IntersectionObserver>>> =
|
let observer: Arc<Mutex<Option<SendWrapper<web_sys::IntersectionObserver>>>> =
|
||||||
Rc::new(RefCell::new(None));
|
Arc::new(Mutex::new(None));
|
||||||
|
|
||||||
let cleanup = {
|
let cleanup = {
|
||||||
let obsserver = Rc::clone(&observer);
|
let observer = Arc::clone(&observer);
|
||||||
|
|
||||||
move || {
|
move || {
|
||||||
if let Some(o) = obsserver.take() {
|
if let Some(o) = observer.lock().unwrap().take() {
|
||||||
o.disconnect();
|
o.disconnect();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -177,7 +179,7 @@ where
|
||||||
obs.observe(&target);
|
obs.observe(&target);
|
||||||
}
|
}
|
||||||
|
|
||||||
observer.replace(Some(obs));
|
*observer.lock().unwrap() = Some(SendWrapper::new(obs));
|
||||||
},
|
},
|
||||||
WatchOptions::default().immediate(immediate),
|
WatchOptions::default().immediate(immediate),
|
||||||
)
|
)
|
||||||
|
|
|
@ -5,6 +5,7 @@ use default_struct_builder::DefaultBuilder;
|
||||||
use leptos::leptos_dom::helpers::IntervalHandle;
|
use leptos::leptos_dom::helpers::IntervalHandle;
|
||||||
use leptos::prelude::diagnostics::SpecialNonReactiveZone;
|
use leptos::prelude::diagnostics::SpecialNonReactiveZone;
|
||||||
use leptos::prelude::*;
|
use leptos::prelude::*;
|
||||||
|
use send_wrapper::SendWrapper;
|
||||||
use std::cell::Cell;
|
use std::cell::Cell;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
@ -140,7 +141,10 @@ where
|
||||||
on_cleanup(stop_watch);
|
on_cleanup(stop_watch);
|
||||||
}
|
}
|
||||||
|
|
||||||
on_cleanup(pause.clone());
|
on_cleanup({
|
||||||
|
let pause = SendWrapper::new(pause.clone());
|
||||||
|
move || pause()
|
||||||
|
});
|
||||||
|
|
||||||
Pausable {
|
Pausable {
|
||||||
is_active: is_active.into(),
|
is_active: is_active.into(),
|
||||||
|
|
|
@ -775,21 +775,21 @@ cfg_if! { if #[cfg(feature = "ssr")] {
|
||||||
impl UseIntlNumberFormatReturn {
|
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.
|
/// 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.
|
/// See [`use_intl_number_format`] for more information.
|
||||||
pub fn format<N>(&self, number: impl Into<MaybeSignal<N>>) -> Signal<String>
|
pub fn format<N>(&self, number: impl Into<MaybeSignal<N>>) -> Signal<String, LocalStorage>
|
||||||
where
|
where
|
||||||
N: Clone + Display + 'static,
|
N: Clone + Display + Send + Sync + 'static,
|
||||||
js_sys::Number: From<N>,
|
js_sys::Number: From<N>,
|
||||||
{
|
{
|
||||||
let number = number.into();
|
let number = number.into();
|
||||||
|
|
||||||
cfg_if! { if #[cfg(feature = "ssr")] {
|
cfg_if! { if #[cfg(feature = "ssr")] {
|
||||||
Signal::derive(move || {
|
Signal::derive_local(move || {
|
||||||
format!("{}", number.get())
|
format!("{}", number.get())
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
let number_format = self.js_intl_number_format.clone();
|
let number_format = self.js_intl_number_format.clone();
|
||||||
|
|
||||||
Signal::derive(move || {
|
Signal::derive_local(move || {
|
||||||
if let Ok(result) = number_format
|
if let Ok(result) = number_format
|
||||||
.format()
|
.format()
|
||||||
.call1(&number_format, &js_sys::Number::from(number.get()).into())
|
.call1(&number_format, &js_sys::Number::from(number.get()).into())
|
||||||
|
@ -852,10 +852,10 @@ impl UseIntlNumberFormatReturn {
|
||||||
&self,
|
&self,
|
||||||
start: impl Into<MaybeSignal<NStart>>,
|
start: impl Into<MaybeSignal<NStart>>,
|
||||||
end: impl Into<MaybeSignal<NEnd>>,
|
end: impl Into<MaybeSignal<NEnd>>,
|
||||||
) -> Signal<String>
|
) -> Signal<String, LocalStorage>
|
||||||
where
|
where
|
||||||
NStart: Clone + Display + 'static,
|
NStart: Clone + Display + Send + Sync + 'static,
|
||||||
NEnd: Clone + Display + 'static,
|
NEnd: Clone + Display + Send + Sync + 'static,
|
||||||
js_sys::Number: From<NStart>,
|
js_sys::Number: From<NStart>,
|
||||||
js_sys::Number: From<NEnd>,
|
js_sys::Number: From<NEnd>,
|
||||||
{
|
{
|
||||||
|
@ -863,13 +863,13 @@ impl UseIntlNumberFormatReturn {
|
||||||
let end = end.into();
|
let end = end.into();
|
||||||
|
|
||||||
cfg_if! { if #[cfg(feature = "ssr")] {
|
cfg_if! { if #[cfg(feature = "ssr")] {
|
||||||
Signal::derive(move || {
|
Signal::derive_local(move || {
|
||||||
format!("{} - {}", start.get(), end.get())
|
format!("{} - {}", start.get(), end.get())
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
let number_format = self.js_intl_number_format.clone();
|
let number_format = self.js_intl_number_format.clone();
|
||||||
|
|
||||||
Signal::derive(move || {
|
Signal::derive_local(move || {
|
||||||
if let Ok(function) = js!(number_format["formatRange"]) {
|
if let Ok(function) = js!(number_format["formatRange"]) {
|
||||||
let function = function.unchecked_into::<js_sys::Function>();
|
let function = function.unchecked_into::<js_sys::Function>();
|
||||||
|
|
||||||
|
|
|
@ -93,7 +93,10 @@ pub fn use_media_query(query: impl Into<MaybeSignal<String>>) -> Signal<bool> {
|
||||||
|
|
||||||
Effect::new(move |_| update());
|
Effect::new(move |_| update());
|
||||||
|
|
||||||
on_cleanup(cleanup);
|
on_cleanup({
|
||||||
|
let cleanup = send_wrapper::SendWrapper::new(cleanup);
|
||||||
|
move || cleanup()
|
||||||
|
});
|
||||||
}}
|
}}
|
||||||
|
|
||||||
matches.into()
|
matches.into()
|
||||||
|
|
|
@ -2,6 +2,7 @@ use crate::core::ElementsMaybeSignal;
|
||||||
use cfg_if::cfg_if;
|
use cfg_if::cfg_if;
|
||||||
use default_struct_builder::DefaultBuilder;
|
use default_struct_builder::DefaultBuilder;
|
||||||
use leptos::prelude::wrappers::read::Signal;
|
use leptos::prelude::wrappers::read::Signal;
|
||||||
|
use send_wrapper::SendWrapper;
|
||||||
use wasm_bindgen::prelude::*;
|
use wasm_bindgen::prelude::*;
|
||||||
|
|
||||||
cfg_if! { if #[cfg(not(feature = "ssr"))] {
|
cfg_if! { if #[cfg(not(feature = "ssr"))] {
|
||||||
|
@ -124,7 +125,7 @@ where
|
||||||
let stop_watch = {
|
let stop_watch = {
|
||||||
let cleanup = cleanup.clone();
|
let cleanup = cleanup.clone();
|
||||||
|
|
||||||
leptos::watch(
|
leptos::prelude::watch(
|
||||||
move || targets.get(),
|
move || targets.get(),
|
||||||
move |targets, _, _| {
|
move |targets, _, _| {
|
||||||
cleanup();
|
cleanup();
|
||||||
|
@ -151,7 +152,10 @@ where
|
||||||
stop_watch();
|
stop_watch();
|
||||||
};
|
};
|
||||||
|
|
||||||
on_cleanup(stop.clone());
|
on_cleanup({
|
||||||
|
let stop = SendWrapper::new(stop.clone());
|
||||||
|
move || stop()
|
||||||
|
});
|
||||||
|
|
||||||
UseMutationObserverReturn { is_supported, stop }
|
UseMutationObserverReturn { is_supported, stop }
|
||||||
}
|
}
|
||||||
|
|
|
@ -138,8 +138,10 @@ pub fn use_raf_fn_with_options(
|
||||||
resume();
|
resume();
|
||||||
}
|
}
|
||||||
|
|
||||||
let pause_cleanup = send_wrapper::SendWrapper::new(pause.clone());
|
on_cleanup({
|
||||||
on_cleanup(move || pause_cleanup());
|
let pause = send_wrapper::SendWrapper::new(pause.clone());
|
||||||
|
move || pause()
|
||||||
|
});
|
||||||
|
|
||||||
Pausable {
|
Pausable {
|
||||||
resume,
|
resume,
|
||||||
|
|
|
@ -153,7 +153,10 @@ where
|
||||||
stop_watch();
|
stop_watch();
|
||||||
};
|
};
|
||||||
|
|
||||||
on_cleanup(stop.clone());
|
on_cleanup({
|
||||||
|
let stop = send_wrapper::SendWrapper::new(stop.clone());
|
||||||
|
move || stop()
|
||||||
|
});
|
||||||
|
|
||||||
UseResizeObserverReturn { is_supported, stop }
|
UseResizeObserverReturn { is_supported, stop }
|
||||||
}
|
}
|
||||||
|
|
|
@ -370,7 +370,7 @@ where
|
||||||
let target = {
|
let target = {
|
||||||
let signal = signal.clone();
|
let signal = signal.clone();
|
||||||
|
|
||||||
Signal::derive(move || {
|
Signal::derive_local(move || {
|
||||||
let element = signal.get();
|
let element = signal.get();
|
||||||
element.map(|element| element.into().unchecked_into::<web_sys::EventTarget>())
|
element.map(|element| element.into().unchecked_into::<web_sys::EventTarget>())
|
||||||
})
|
})
|
||||||
|
@ -392,14 +392,14 @@ where
|
||||||
|
|
||||||
let _ = use_event_listener_with_options::<
|
let _ = use_event_listener_with_options::<
|
||||||
_,
|
_,
|
||||||
Signal<Option<web_sys::EventTarget>>,
|
Signal<Option<web_sys::EventTarget>, LocalStorage>,
|
||||||
web_sys::EventTarget,
|
web_sys::EventTarget,
|
||||||
_,
|
_,
|
||||||
>(target, ev::scroll, handler, options.event_listener_options);
|
>(target, ev::scroll, handler, options.event_listener_options);
|
||||||
} else {
|
} else {
|
||||||
let _ = use_event_listener_with_options::<
|
let _ = use_event_listener_with_options::<
|
||||||
_,
|
_,
|
||||||
Signal<Option<web_sys::EventTarget>>,
|
Signal<Option<web_sys::EventTarget>, LocalStorage>,
|
||||||
web_sys::EventTarget,
|
web_sys::EventTarget,
|
||||||
_,
|
_,
|
||||||
>(
|
>(
|
||||||
|
@ -412,7 +412,7 @@ where
|
||||||
|
|
||||||
let _ = use_event_listener_with_options::<
|
let _ = use_event_listener_with_options::<
|
||||||
_,
|
_,
|
||||||
Signal<Option<web_sys::EventTarget>>,
|
Signal<Option<web_sys::EventTarget>, LocalStorage>,
|
||||||
web_sys::EventTarget,
|
web_sys::EventTarget,
|
||||||
_,
|
_,
|
||||||
>(
|
>(
|
||||||
|
|
|
@ -146,7 +146,7 @@ pub fn use_service_worker_with_options(
|
||||||
check_for_update: move || {
|
check_for_update: move || {
|
||||||
registration.with(|reg| {
|
registration.with(|reg| {
|
||||||
if let Ok(reg) = 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<ServiceWorkerRegistration>,
|
SendWrapper<ServiceWorkerRegistration>,
|
||||||
Result<SendWrapper<ServiceWorkerRegistration>, SendWrapper<JsValue>>,
|
Result<SendWrapper<ServiceWorkerRegistration>, SendWrapper<JsValue>>,
|
||||||
> {
|
> {
|
||||||
Action::new(
|
Action::new_unsync(
|
||||||
move |registration: &SendWrapper<ServiceWorkerRegistration>| {
|
move |registration: &SendWrapper<ServiceWorkerRegistration>| {
|
||||||
let registration = registration.clone();
|
let registration = registration.clone();
|
||||||
async move {
|
async move {
|
||||||
|
@ -256,7 +256,7 @@ fn create_action_update() -> Action<
|
||||||
.and_then(|ok| ok.dyn_into::<ServiceWorkerRegistration>())
|
.and_then(|ok| ok.dyn_into::<ServiceWorkerRegistration>())
|
||||||
.map(SendWrapper::new)
|
.map(SendWrapper::new)
|
||||||
.map_err(SendWrapper::new),
|
.map_err(SendWrapper::new),
|
||||||
Err(err) => Err(err),
|
Err(err) => Err(SendWrapper::new(err)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -268,15 +268,17 @@ fn create_action_create_or_update_registration() -> Action<
|
||||||
ServiceWorkerScriptUrl,
|
ServiceWorkerScriptUrl,
|
||||||
Result<SendWrapper<ServiceWorkerRegistration>, SendWrapper<JsValue>>,
|
Result<SendWrapper<ServiceWorkerRegistration>, SendWrapper<JsValue>>,
|
||||||
> {
|
> {
|
||||||
Action::new(move |script_url: &ServiceWorkerScriptUrl| {
|
Action::new_unsync(move |script_url: &ServiceWorkerScriptUrl| {
|
||||||
let script_url = script_url.0.to_owned();
|
let script_url = script_url.0.to_owned();
|
||||||
async move {
|
async move {
|
||||||
if let Some(navigator) = use_window().navigator() {
|
if let Some(navigator) = use_window().navigator() {
|
||||||
js_fut!(navigator.service_worker().register(script_url.as_str()))
|
js_fut!(navigator.service_worker().register(script_url.as_str()))
|
||||||
.await
|
.await
|
||||||
.and_then(|ok| ok.dyn_into::<ServiceWorkerRegistration>())
|
.and_then(|ok| ok.dyn_into::<ServiceWorkerRegistration>())
|
||||||
|
.map(SendWrapper::new)
|
||||||
|
.map_err(SendWrapper::new)
|
||||||
} else {
|
} else {
|
||||||
Err(JsValue::from_str("no navigator"))
|
Err(SendWrapper::new(JsValue::from_str("no navigator")))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -285,7 +287,7 @@ fn create_action_create_or_update_registration() -> Action<
|
||||||
/// A leptos action which asynchronously fetches the current ServiceWorkerRegistration.
|
/// A leptos action which asynchronously fetches the current ServiceWorkerRegistration.
|
||||||
fn create_action_get_registration(
|
fn create_action_get_registration(
|
||||||
) -> Action<(), Result<SendWrapper<ServiceWorkerRegistration>, SendWrapper<JsValue>>> {
|
) -> Action<(), Result<SendWrapper<ServiceWorkerRegistration>, SendWrapper<JsValue>>> {
|
||||||
Action::new(move |(): &()| async move {
|
Action::new_unsync(move |(): &()| async move {
|
||||||
if let Some(navigator) = use_window().navigator() {
|
if let Some(navigator) = use_window().navigator() {
|
||||||
js_fut!(navigator.service_worker().get_registration())
|
js_fut!(navigator.service_worker().get_registration())
|
||||||
.await
|
.await
|
||||||
|
|
|
@ -78,7 +78,7 @@ pub fn use_sorted<S, I, T>(iterable: S) -> Signal<I>
|
||||||
where
|
where
|
||||||
S: Into<MaybeSignal<I>>,
|
S: Into<MaybeSignal<I>>,
|
||||||
T: Ord,
|
T: Ord,
|
||||||
I: DerefMut<Target = [T]> + Clone + PartialEq,
|
I: DerefMut<Target = [T]> + Clone + PartialEq + Send + Sync + 'static,
|
||||||
{
|
{
|
||||||
let iterable = iterable.into();
|
let iterable = iterable.into();
|
||||||
|
|
||||||
|
@ -93,8 +93,8 @@ where
|
||||||
pub fn use_sorted_by<S, I, T, F>(iterable: S, cmp_fn: F) -> Signal<I>
|
pub fn use_sorted_by<S, I, T, F>(iterable: S, cmp_fn: F) -> Signal<I>
|
||||||
where
|
where
|
||||||
S: Into<MaybeSignal<I>>,
|
S: Into<MaybeSignal<I>>,
|
||||||
I: DerefMut<Target = [T]> + Clone + PartialEq,
|
I: DerefMut<Target = [T]> + Clone + PartialEq + Send + Sync + 'static,
|
||||||
F: FnMut(&T, &T) -> Ordering + Clone + 'static,
|
F: FnMut(&T, &T) -> Ordering + Clone + Send + Sync + 'static,
|
||||||
{
|
{
|
||||||
let iterable = iterable.into();
|
let iterable = iterable.into();
|
||||||
|
|
||||||
|
@ -109,9 +109,9 @@ where
|
||||||
pub fn use_sorted_by_key<S, I, T, K, F>(iterable: S, key_fn: F) -> Signal<I>
|
pub fn use_sorted_by_key<S, I, T, K, F>(iterable: S, key_fn: F) -> Signal<I>
|
||||||
where
|
where
|
||||||
S: Into<MaybeSignal<I>>,
|
S: Into<MaybeSignal<I>>,
|
||||||
I: DerefMut<Target = [T]> + Clone + PartialEq,
|
I: DerefMut<Target = [T]> + Clone + PartialEq + Send + Sync + 'static,
|
||||||
K: Ord,
|
K: Ord,
|
||||||
F: FnMut(&T) -> K + Clone + 'static,
|
F: FnMut(&T) -> K + Clone + Send + Sync + 'static,
|
||||||
{
|
{
|
||||||
let iterable = iterable.into();
|
let iterable = iterable.into();
|
||||||
|
|
||||||
|
|
|
@ -20,7 +20,7 @@ use leptos::prelude::*;
|
||||||
/// # view! { }
|
/// # view! { }
|
||||||
/// # }
|
/// # }
|
||||||
/// ```
|
/// ```
|
||||||
pub fn use_supported(callback: impl Fn() -> bool + 'static) -> Signal<bool> {
|
pub fn use_supported(callback: impl Fn() -> bool + Send + Sync + 'static) -> Signal<bool> {
|
||||||
#[cfg(feature = "ssr")]
|
#[cfg(feature = "ssr")]
|
||||||
{
|
{
|
||||||
let _ = callback;
|
let _ = callback;
|
||||||
|
|
|
@ -59,7 +59,7 @@ pub fn use_user_media_with_options(
|
||||||
|
|
||||||
let (enabled, set_enabled) = enabled.into_signal();
|
let (enabled, set_enabled) = enabled.into_signal();
|
||||||
|
|
||||||
let (stream, set_stream) = signal(None::<Result<web_sys::MediaStream, JsValue>>);
|
let (stream, set_stream) = signal_local(None::<Result<web_sys::MediaStream, JsValue>>);
|
||||||
|
|
||||||
let _start = move || async move {
|
let _start = move || async move {
|
||||||
cfg_if! { if #[cfg(not(feature = "ssr"))] {
|
cfg_if! { if #[cfg(not(feature = "ssr"))] {
|
||||||
|
@ -187,7 +187,7 @@ where
|
||||||
/// Initially this is `None` until `start` resolved successfully.
|
/// 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,
|
/// In case the stream couldn't be started, for example because the user didn't grant permission,
|
||||||
/// this has the value `Some(Err(...))`.
|
/// this has the value `Some(Err(...))`.
|
||||||
pub stream: Signal<Option<Result<web_sys::MediaStream, JsValue>>>,
|
pub stream: Signal<Option<Result<web_sys::MediaStream, JsValue>>, LocalStorage>,
|
||||||
|
|
||||||
/// Starts the screen streaming. Triggers the ask for permission if not already granted.
|
/// Starts the screen streaming. Triggers the ask for permission if not already granted.
|
||||||
pub start: StartFn,
|
pub start: StartFn,
|
||||||
|
|
|
@ -2,7 +2,6 @@ use crate::{use_supported, use_window};
|
||||||
use cfg_if::cfg_if;
|
use cfg_if::cfg_if;
|
||||||
use default_struct_builder::DefaultBuilder;
|
use default_struct_builder::DefaultBuilder;
|
||||||
use leptos::prelude::{wrappers::read::Signal, *};
|
use leptos::prelude::{wrappers::read::Signal, *};
|
||||||
use send_wrapper::SendWrapper;
|
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
/// Reactive [Notification API](https://developer.mozilla.org/en-US/docs/Web/API/Notification).
|
/// 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<impl Fn(ShowOptions) + Clone, impl Fn() + Clone> {
|
) -> UseWebNotificationReturn<impl Fn(ShowOptions) + Clone, impl Fn() + Clone> {
|
||||||
let is_supported = use_supported(browser_supports_notifications);
|
let is_supported = use_supported(browser_supports_notifications);
|
||||||
|
|
||||||
let (notification, set_notification) = signal(None::<SendWrapper<web_sys::Notification>>);
|
let (notification, set_notification) = signal_local(None::<web_sys::Notification>);
|
||||||
|
|
||||||
let (permission, set_permission) = signal(NotificationPermission::default());
|
let (permission, set_permission) = signal(NotificationPermission::default());
|
||||||
|
|
||||||
|
@ -462,7 +461,7 @@ where
|
||||||
CloseFn: Fn() + Clone,
|
CloseFn: Fn() + Clone,
|
||||||
{
|
{
|
||||||
pub is_supported: Signal<bool>,
|
pub is_supported: Signal<bool>,
|
||||||
pub notification: Signal<Option<SendWrapper<web_sys::Notification>>>,
|
pub notification: Signal<Option<web_sys::Notification>, LocalStorage>,
|
||||||
pub show: ShowFn,
|
pub show: ShowFn,
|
||||||
pub close: CloseFn,
|
pub close: CloseFn,
|
||||||
pub permission: Signal<NotificationPermission>,
|
pub permission: Signal<NotificationPermission>,
|
||||||
|
|
|
@ -2,7 +2,6 @@
|
||||||
|
|
||||||
use cfg_if::cfg_if;
|
use cfg_if::cfg_if;
|
||||||
use leptos::{leptos_dom::helpers::TimeoutHandle, prelude::*};
|
use leptos::{leptos_dom::helpers::TimeoutHandle, prelude::*};
|
||||||
use send_wrapper::SendWrapper;
|
|
||||||
use std::sync::{atomic::AtomicBool, Arc};
|
use std::sync::{atomic::AtomicBool, Arc};
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
@ -238,7 +237,7 @@ pub fn use_websocket<T, C>(
|
||||||
impl Fn(&T) + Clone + 'static,
|
impl Fn(&T) + Clone + 'static,
|
||||||
>
|
>
|
||||||
where
|
where
|
||||||
T: 'static,
|
T: Send + Sync + 'static,
|
||||||
C: Encoder<T> + Decoder<T>,
|
C: Encoder<T> + Decoder<T>,
|
||||||
C: IsBinary<T, <C as Decoder<T>>::Encoded>,
|
C: IsBinary<T, <C as Decoder<T>>::Encoded>,
|
||||||
C: HybridDecoder<T, <C as Decoder<T>>::Encoded, Error = <C as Decoder<T>>::Error>,
|
C: HybridDecoder<T, <C as Decoder<T>>::Encoded, Error = <C as Decoder<T>>::Error>,
|
||||||
|
@ -263,7 +262,7 @@ pub fn use_websocket_with_options<T, C>(
|
||||||
impl Fn(&T) + Clone + 'static,
|
impl Fn(&T) + Clone + 'static,
|
||||||
>
|
>
|
||||||
where
|
where
|
||||||
T: 'static,
|
T: Send + Sync + 'static,
|
||||||
C: Encoder<T> + Decoder<T>,
|
C: Encoder<T> + Decoder<T>,
|
||||||
C: IsBinary<T, <C as Decoder<T>>::Encoded>,
|
C: IsBinary<T, <C as Decoder<T>>::Encoded>,
|
||||||
C: HybridDecoder<T, <C as Decoder<T>>::Encoded, Error = <C as Decoder<T>>::Error>,
|
C: HybridDecoder<T, <C as Decoder<T>>::Encoded, Error = <C as Decoder<T>>::Error>,
|
||||||
|
@ -286,7 +285,7 @@ where
|
||||||
|
|
||||||
let (ready_state, set_ready_state) = signal(ConnectionReadyState::Closed);
|
let (ready_state, set_ready_state) = signal(ConnectionReadyState::Closed);
|
||||||
let (message, set_message) = signal(None);
|
let (message, set_message) = signal(None);
|
||||||
let ws_ref: StoredValue<Option<SendWrapper<WebSocket>>> = StoredValue::new(None);
|
let ws_ref: StoredValue<Option<WebSocket>, _> = StoredValue::new_local(None);
|
||||||
|
|
||||||
let reconnect_timer_ref: StoredValue<Option<TimeoutHandle>> = StoredValue::new(None);
|
let reconnect_timer_ref: StoredValue<Option<TimeoutHandle>> = StoredValue::new(None);
|
||||||
|
|
||||||
|
@ -305,9 +304,9 @@ where
|
||||||
Some(Arc::new(move || {
|
Some(Arc::new(move || {
|
||||||
if !manually_closed_ref.get_value()
|
if !manually_closed_ref.get_value()
|
||||||
&& !reconnect_limit.is_exceeded_by(reconnect_times_ref.get_value())
|
&& !reconnect_limit.is_exceeded_by(reconnect_times_ref.get_value())
|
||||||
&& ws_ref.get_value().map_or(false, |ws: SendWrapper<WebSocket>| {
|
&& ws_ref
|
||||||
ws.ready_state() != WebSocket::OPEN
|
.get_value()
|
||||||
})
|
.map_or(false, |ws: WebSocket| ws.ready_state() != WebSocket::OPEN)
|
||||||
{
|
{
|
||||||
reconnect_timer_ref.set_value(
|
reconnect_timer_ref.set_value(
|
||||||
set_timeout_with_handle(
|
set_timeout_with_handle(
|
||||||
|
@ -358,7 +357,7 @@ where
|
||||||
let on_open = Arc::clone(&on_open);
|
let on_open = Arc::clone(&on_open);
|
||||||
|
|
||||||
let onopen_closure = Closure::wrap(Box::new(move |e: Event| {
|
let onopen_closure = Closure::wrap(Box::new(move |e: Event| {
|
||||||
if unmounted.get() {
|
if unmounted.load(std::sync::atomic::Ordering::Relaxed) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -387,7 +386,7 @@ where
|
||||||
let on_error = Arc::clone(&on_error);
|
let on_error = Arc::clone(&on_error);
|
||||||
|
|
||||||
let onmessage_closure = Closure::wrap(Box::new(move |e: MessageEvent| {
|
let onmessage_closure = Closure::wrap(Box::new(move |e: MessageEvent| {
|
||||||
if unmounted.get() {
|
if unmounted.load(std::sync::atomic::Ordering::Relaxed) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -409,17 +408,18 @@ where
|
||||||
on_message_raw(&txt);
|
on_message_raw(&txt);
|
||||||
|
|
||||||
#[cfg(debug_assertions)]
|
#[cfg(debug_assertions)]
|
||||||
SpecialNonReactiveZone::exit(prev);
|
drop(zone);
|
||||||
|
|
||||||
match C::decode_str(&txt) {
|
match C::decode_str(&txt) {
|
||||||
Ok(val) => {
|
Ok(val) => {
|
||||||
#[cfg(debug_assertions)]
|
#[cfg(debug_assertions)]
|
||||||
let prev = SpecialNonReactiveZone::enter();
|
let prev =
|
||||||
|
diagnostics::SpecialNonReactiveZone::enter();
|
||||||
|
|
||||||
on_message(&val);
|
on_message(&val);
|
||||||
|
|
||||||
#[cfg(debug_assertions)]
|
#[cfg(debug_assertions)]
|
||||||
drop(zone);
|
drop(prev);
|
||||||
|
|
||||||
set_message.set(Some(val));
|
set_message.set(Some(val));
|
||||||
}
|
}
|
||||||
|
@ -445,12 +445,12 @@ where
|
||||||
match C::decode_bin(array.as_slice()) {
|
match C::decode_bin(array.as_slice()) {
|
||||||
Ok(val) => {
|
Ok(val) => {
|
||||||
#[cfg(debug_assertions)]
|
#[cfg(debug_assertions)]
|
||||||
let prev = SpecialNonReactiveZone::enter();
|
let prev = diagnostics::SpecialNonReactiveZone::enter();
|
||||||
|
|
||||||
on_message(&val);
|
on_message(&val);
|
||||||
|
|
||||||
#[cfg(debug_assertions)]
|
#[cfg(debug_assertions)]
|
||||||
SpecialNonReactiveZone::exit(prev);
|
drop(prev);
|
||||||
|
|
||||||
set_message.set(Some(val));
|
set_message.set(Some(val));
|
||||||
}
|
}
|
||||||
|
@ -472,7 +472,7 @@ where
|
||||||
let on_error = Arc::clone(&on_error);
|
let on_error = Arc::clone(&on_error);
|
||||||
|
|
||||||
let onerror_closure = Closure::wrap(Box::new(move |e: Event| {
|
let onerror_closure = Closure::wrap(Box::new(move |e: Event| {
|
||||||
if unmounted.get() {
|
if unmounted.load(std::sync::atomic::Ordering::Relaxed) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -501,7 +501,7 @@ where
|
||||||
let on_close = Arc::clone(&on_close);
|
let on_close = Arc::clone(&on_close);
|
||||||
|
|
||||||
let onclose_closure = Closure::wrap(Box::new(move |e: CloseEvent| {
|
let onclose_closure = Closure::wrap(Box::new(move |e: CloseEvent| {
|
||||||
if unmounted.get() {
|
if unmounted.load(std::sync::atomic::Ordering::Relaxed) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -630,7 +630,7 @@ impl ReconnectLimit {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type ArcFnBytes = Arc<dyn Fn(&[u8])>;
|
type ArcFnBytes = Arc<dyn Fn(&[u8]) + Send + Sync>;
|
||||||
|
|
||||||
/// Options for [`use_websocket_with_options`].
|
/// Options for [`use_websocket_with_options`].
|
||||||
#[derive(DefaultBuilder)]
|
#[derive(DefaultBuilder)]
|
||||||
|
@ -642,11 +642,11 @@ where
|
||||||
on_open: Arc<dyn Fn(Event) + Send + Sync>,
|
on_open: Arc<dyn Fn(Event) + Send + Sync>,
|
||||||
/// `WebSocket` message callback for typed message decoded by codec.
|
/// `WebSocket` message callback for typed message decoded by codec.
|
||||||
#[builder(skip)]
|
#[builder(skip)]
|
||||||
on_message: Arc<dyn Fn(&T)>,
|
on_message: Arc<dyn Fn(&T) + Send + Sync>,
|
||||||
/// `WebSocket` message callback for text.
|
/// `WebSocket` message callback for text.
|
||||||
on_message_raw: Arc<dyn Fn(&str) + Send + Sync>,
|
on_message_raw: Arc<dyn Fn(&str) + Send + Sync>,
|
||||||
/// `WebSocket` message callback for binary.
|
/// `WebSocket` message callback for binary.
|
||||||
on_message_raw_bytes: ArcFnBytes + Send + Sync,
|
on_message_raw_bytes: ArcFnBytes,
|
||||||
/// `WebSocket` error callback.
|
/// `WebSocket` error callback.
|
||||||
#[builder(skip)]
|
#[builder(skip)]
|
||||||
on_error: Arc<dyn Fn(UseWebSocketError<E, D>) + Send + Sync>,
|
on_error: Arc<dyn Fn(UseWebSocketError<E, D>) + Send + Sync>,
|
||||||
|
@ -669,7 +669,7 @@ impl<T: ?Sized, E, D> UseWebSocketOptions<T, E, D> {
|
||||||
/// `WebSocket` error callback.
|
/// `WebSocket` error callback.
|
||||||
pub fn on_error<F>(self, handler: F) -> Self
|
pub fn on_error<F>(self, handler: F) -> Self
|
||||||
where
|
where
|
||||||
F: Fn(UseWebSocketError<E, D>) + 'static,
|
F: Fn(UseWebSocketError<E, D>) + Send + Sync + 'static,
|
||||||
{
|
{
|
||||||
Self {
|
Self {
|
||||||
on_error: Arc::new(handler),
|
on_error: Arc::new(handler),
|
||||||
|
@ -680,7 +680,7 @@ impl<T: ?Sized, E, D> UseWebSocketOptions<T, E, D> {
|
||||||
/// `WebSocket` message callback for typed message decoded by codec.
|
/// `WebSocket` message callback for typed message decoded by codec.
|
||||||
pub fn on_message<F>(self, handler: F) -> Self
|
pub fn on_message<F>(self, handler: F) -> Self
|
||||||
where
|
where
|
||||||
F: Fn(&T) + 'static,
|
F: Fn(&T) + Send + Sync + 'static,
|
||||||
{
|
{
|
||||||
Self {
|
Self {
|
||||||
on_message: Arc::new(handler),
|
on_message: Arc::new(handler),
|
||||||
|
@ -710,7 +710,7 @@ impl<T: ?Sized, E, D> Default for UseWebSocketOptions<T, E, D> {
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct UseWebSocketReturn<T, OpenFn, CloseFn, SendFn>
|
pub struct UseWebSocketReturn<T, OpenFn, CloseFn, SendFn>
|
||||||
where
|
where
|
||||||
T: 'static,
|
T: Send + Sync + 'static,
|
||||||
OpenFn: Fn() + Clone + 'static,
|
OpenFn: Fn() + Clone + 'static,
|
||||||
CloseFn: Fn() + Clone + 'static,
|
CloseFn: Fn() + Clone + 'static,
|
||||||
SendFn: Fn(&T) + Clone + 'static,
|
SendFn: Fn(&T) + Clone + 'static,
|
||||||
|
@ -720,7 +720,7 @@ where
|
||||||
/// Latest message received from `WebSocket`.
|
/// Latest message received from `WebSocket`.
|
||||||
pub message: Signal<Option<T>>,
|
pub message: Signal<Option<T>>,
|
||||||
/// The `WebSocket` instance.
|
/// The `WebSocket` instance.
|
||||||
pub ws: Option<SendWrapper<WebSocket>>,
|
pub ws: Option<WebSocket>,
|
||||||
/// Opens the `WebSocket` connection
|
/// Opens the `WebSocket` connection
|
||||||
pub open: OpenFn,
|
pub open: OpenFn,
|
||||||
/// Closes the `WebSocket` connection
|
/// Closes the `WebSocket` connection
|
||||||
|
|
|
@ -15,7 +15,7 @@ macro_rules! signal_filtered {
|
||||||
) -> Signal<T>
|
) -> Signal<T>
|
||||||
where
|
where
|
||||||
S: Into<Signal<T>>,
|
S: Into<Signal<T>>,
|
||||||
T: Clone + 'static,
|
T: Clone + Send + Sync + 'static,
|
||||||
{
|
{
|
||||||
[<signal_ $filter_name d_with_options>](value, ms, [<$filter_name:camel Options>]::default())
|
[<signal_ $filter_name d_with_options>](value, ms, [<$filter_name:camel Options>]::default())
|
||||||
}
|
}
|
||||||
|
@ -36,7 +36,7 @@ macro_rules! signal_filtered {
|
||||||
) -> Signal<T>
|
) -> Signal<T>
|
||||||
where
|
where
|
||||||
S: Into<Signal<T>>,
|
S: Into<Signal<T>>,
|
||||||
T: Clone + 'static,
|
T: Clone + Send + Sync + 'static,
|
||||||
{
|
{
|
||||||
let value = value.into();
|
let value = value.into();
|
||||||
let ms = ms.into();
|
let ms = ms.into();
|
||||||
|
|
|
@ -11,6 +11,7 @@ macro_rules! use_derive_signal {
|
||||||
$(#[$outer])*
|
$(#[$outer])*
|
||||||
pub fn $name<V $(, $( $type_param ),* )? >(value: V) -> Signal<$return_type>
|
pub fn $name<V $(, $( $type_param ),* )? >(value: V) -> Signal<$return_type>
|
||||||
where
|
where
|
||||||
|
$inner_signal_type $(< $( $inner_type_param ),+ >)?: Send + Sync,
|
||||||
V: Into<MaybeSignal<$inner_signal_type $(< $( $inner_type_param ),+ >)?>> $(, $( $type_param $( : $first_bound $(+ $rest_bound)* )? ),+ )?
|
V: Into<MaybeSignal<$inner_signal_type $(< $( $inner_type_param ),+ >)?>> $(, $( $type_param $( : $first_bound $(+ $rest_bound)* )? ),+ )?
|
||||||
{
|
{
|
||||||
let value = value.into();
|
let value = value.into();
|
||||||
|
|
|
@ -129,7 +129,7 @@ where
|
||||||
let filtered_callback =
|
let filtered_callback =
|
||||||
create_filter_wrapper(options.filter.filter_fn(), wrapped_callback.clone());
|
create_filter_wrapper(options.filter.filter_fn(), wrapped_callback.clone());
|
||||||
|
|
||||||
leptos::watch(
|
leptos::prelude::watch(
|
||||||
deps,
|
deps,
|
||||||
move |deps_value, previous_deps_value, did_run_before| {
|
move |deps_value, previous_deps_value, did_run_before| {
|
||||||
cur_deps_value.replace(Some(deps_value.clone()));
|
cur_deps_value.replace(Some(deps_value.clone()));
|
||||||
|
@ -138,7 +138,7 @@ where
|
||||||
let callback_value = if options.immediate && did_run_before.is_none() {
|
let callback_value = if options.immediate && did_run_before.is_none() {
|
||||||
Some(wrapped_callback())
|
Some(wrapped_callback())
|
||||||
} else {
|
} else {
|
||||||
filtered_callback().take()
|
filtered_callback().lock().unwrap().take()
|
||||||
};
|
};
|
||||||
|
|
||||||
prev_callback_value.replace(callback_value);
|
prev_callback_value.replace(callback_value);
|
||||||
|
@ -196,5 +196,5 @@ where
|
||||||
W: Clone + 'static,
|
W: Clone + 'static,
|
||||||
T: Clone + 'static,
|
T: Clone + 'static,
|
||||||
{
|
{
|
||||||
leptos::watch(deps, callback, false)
|
leptos::prelude::watch(deps, callback, false)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue