mirror of
https://github.com/adoyle0/leptos-use.git
synced 2025-01-23 09:09:21 -05:00
Merge pull request #133 from CorvusPrudens/leptos-0.7-alpha
Progress towards Leptos 0.7.0-alpha
This commit is contained in:
commit
3fdd941f47
37 changed files with 343 additions and 429 deletions
|
@ -26,14 +26,15 @@ http1 = { version = "1", optional = true, package = "http" }
|
|||
http0_2 = { version = "0.2", optional = true, package = "http" }
|
||||
js-sys = "0.3"
|
||||
lazy_static = "1"
|
||||
leptos = { version = "0.7.0-preview2", path = "../leptos/leptos" }
|
||||
leptos_axum = { version = "0.7.0-preview2", optional = true }
|
||||
leptos = { version = "0.7.0-alpha" }
|
||||
leptos_axum = { version = "0.7.0-alpha", optional = true }
|
||||
leptos_actix = { version = "0.6", optional = true }
|
||||
leptos-spin = { version = "0.2", optional = true }
|
||||
num = { version = "0.4", optional = true }
|
||||
paste = "1"
|
||||
prost = { version = "0.12", optional = true }
|
||||
rmp-serde = { version = "1.1", optional = true }
|
||||
send_wrapper = "0.6.0"
|
||||
serde = { version = "1", optional = true }
|
||||
serde_json = { version = "1", optional = true }
|
||||
thiserror = "1"
|
||||
|
@ -133,7 +134,7 @@ features = [
|
|||
|
||||
[dev-dependencies]
|
||||
getrandom = { version = "0.2", features = ["js"] }
|
||||
leptos_meta = "0.7.0-preview2"
|
||||
leptos_meta = "0.7.0-alpha"
|
||||
rand = "0.8"
|
||||
|
||||
[features]
|
||||
|
|
|
@ -44,30 +44,16 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
impl<T, E> SignalGet for ElementMaybeSignal<T, E>
|
||||
impl<T, E> DefinedAt for ElementMaybeSignal<T, E>
|
||||
where
|
||||
T: Into<E> + Clone + 'static,
|
||||
{
|
||||
type Value = Option<T>;
|
||||
|
||||
fn get(&self) -> Option<T> {
|
||||
match self {
|
||||
Self::Static(t) => t.clone(),
|
||||
Self::Dynamic(s) => s.get(),
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
fn try_get(&self) -> Option<Option<T>> {
|
||||
match self {
|
||||
Self::Static(t) => Some(t.clone()),
|
||||
Self::Dynamic(s) => s.try_get(),
|
||||
_ => unreachable!(),
|
||||
}
|
||||
fn defined_at(&self) -> Option<&'static std::panic::Location<'static>> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, E> SignalWith for ElementMaybeSignal<T, E>
|
||||
impl<T, E> With for ElementMaybeSignal<T, E>
|
||||
where
|
||||
T: Into<E> + Clone + 'static,
|
||||
{
|
||||
|
@ -90,7 +76,7 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
impl<T, E> SignalWithUntracked for ElementMaybeSignal<T, E>
|
||||
impl<T, E> WithUntracked for ElementMaybeSignal<T, E>
|
||||
where
|
||||
T: Into<E> + Clone + 'static,
|
||||
{
|
||||
|
@ -113,29 +99,6 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
impl<T, E> SignalGetUntracked for ElementMaybeSignal<T, E>
|
||||
where
|
||||
T: Into<E> + Clone + 'static,
|
||||
{
|
||||
type Value = Option<T>;
|
||||
|
||||
fn get_untracked(&self) -> Option<T> {
|
||||
match self {
|
||||
Self::Static(t) => t.clone(),
|
||||
Self::Dynamic(s) => s.get_untracked(),
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
fn try_get_untracked(&self) -> Option<Option<T>> {
|
||||
match self {
|
||||
Self::Static(t) => Some(t.clone()),
|
||||
Self::Dynamic(s) => s.try_get_untracked(),
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// From static element //////////////////////////////////////////////////////////////
|
||||
|
||||
impl<T, E> From<T> for ElementMaybeSignal<T, E>
|
||||
|
|
|
@ -45,30 +45,16 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
impl<T, E> SignalGet for ElementsMaybeSignal<T, E>
|
||||
impl<T, E> DefinedAt for ElementsMaybeSignal<T, E>
|
||||
where
|
||||
T: Into<E> + Clone + 'static,
|
||||
{
|
||||
type Value = Vec<Option<T>>;
|
||||
|
||||
fn get(&self) -> Vec<Option<T>> {
|
||||
match self {
|
||||
Self::Static(v) => v.clone(),
|
||||
Self::Dynamic(s) => s.get(),
|
||||
Self::_Phantom(_) => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
fn try_get(&self) -> Option<Vec<Option<T>>> {
|
||||
match self {
|
||||
Self::Static(v) => Some(v.clone()),
|
||||
Self::Dynamic(s) => s.try_get(),
|
||||
Self::_Phantom(_) => unreachable!(),
|
||||
}
|
||||
fn defined_at(&self) -> Option<&'static std::panic::Location<'static>> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, E> SignalWith for ElementsMaybeSignal<T, E>
|
||||
impl<T, E> With for ElementsMaybeSignal<T, E>
|
||||
where
|
||||
T: Into<E> + Clone + 'static,
|
||||
{
|
||||
|
@ -91,7 +77,7 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
impl<T, E> SignalWithUntracked for ElementsMaybeSignal<T, E>
|
||||
impl<T, E> WithUntracked for ElementsMaybeSignal<T, E>
|
||||
where
|
||||
T: Into<E> + Clone + 'static,
|
||||
{
|
||||
|
@ -114,29 +100,6 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
impl<T, E> SignalGetUntracked for ElementsMaybeSignal<T, E>
|
||||
where
|
||||
T: Into<E> + Clone + 'static,
|
||||
{
|
||||
type Value = Vec<Option<T>>;
|
||||
|
||||
fn get_untracked(&self) -> Vec<Option<T>> {
|
||||
match self {
|
||||
Self::Static(t) => t.clone(),
|
||||
Self::Dynamic(s) => s.get_untracked(),
|
||||
Self::_Phantom(_) => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
fn try_get_untracked(&self) -> Option<Vec<Option<T>>> {
|
||||
match self {
|
||||
Self::Static(t) => Some(t.clone()),
|
||||
Self::Dynamic(s) => s.try_get_untracked(),
|
||||
Self::_Phantom(_) => unreachable!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// From single static element //////////////////////////////////////////////////////////////
|
||||
|
||||
impl<T, E> From<T> for ElementsMaybeSignal<T, E>
|
||||
|
|
|
@ -93,7 +93,7 @@ impl<T: Clone> MaybeRwSignal<T> {
|
|||
Self::DynamicRead(s) => {
|
||||
let (r, w) = signal(s.get_untracked());
|
||||
|
||||
create_effect(move |_| {
|
||||
Effect::new(move |_| {
|
||||
w.update(move |w| {
|
||||
*w = s.get();
|
||||
});
|
||||
|
|
|
@ -37,49 +37,17 @@ impl<T> Clone for UseRwSignal<T> {
|
|||
|
||||
impl<T> Copy for UseRwSignal<T> {}
|
||||
|
||||
impl<T> SignalGet for UseRwSignal<T>
|
||||
where
|
||||
T: Clone,
|
||||
{
|
||||
type Value = T;
|
||||
|
||||
fn get(&self) -> T {
|
||||
impl<T> DefinedAt for UseRwSignal<T> {
|
||||
fn defined_at(&self) -> Option<&'static std::panic::Location<'static>> {
|
||||
match self {
|
||||
Self::Separate(s, _) => s.get(),
|
||||
Self::Combined(s) => s.get(),
|
||||
}
|
||||
}
|
||||
|
||||
fn try_get(&self) -> Option<T> {
|
||||
match self {
|
||||
Self::Separate(s, _) => s.try_get(),
|
||||
Self::Combined(s) => s.try_get(),
|
||||
Self::Combined(s) => s.defined_at(),
|
||||
// NOTE: is this sufficient communication?
|
||||
Self::Separate(_, s) => s.defined_at(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> SignalGetUntracked for UseRwSignal<T>
|
||||
where
|
||||
T: Clone,
|
||||
{
|
||||
type Value = T;
|
||||
|
||||
fn get_untracked(&self) -> T {
|
||||
match self {
|
||||
Self::Separate(s, _) => s.get_untracked(),
|
||||
Self::Combined(s) => s.get_untracked(),
|
||||
}
|
||||
}
|
||||
|
||||
fn try_get_untracked(&self) -> Option<T> {
|
||||
match self {
|
||||
Self::Separate(s, _) => s.try_get_untracked(),
|
||||
Self::Combined(s) => s.try_get_untracked(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> SignalWith for UseRwSignal<T> {
|
||||
impl<T> With for UseRwSignal<T> {
|
||||
type Value = T;
|
||||
|
||||
fn with<R>(&self, f: impl FnOnce(&T) -> R) -> R {
|
||||
|
@ -97,7 +65,7 @@ impl<T> SignalWith for UseRwSignal<T> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T> SignalWithUntracked for UseRwSignal<T> {
|
||||
impl<T> WithUntracked for UseRwSignal<T> {
|
||||
type Value = T;
|
||||
|
||||
fn with_untracked<R>(&self, f: impl FnOnce(&T) -> R) -> R {
|
||||
|
@ -115,7 +83,7 @@ impl<T> SignalWithUntracked for UseRwSignal<T> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T> SignalSet for UseRwSignal<T> {
|
||||
impl<T> Set for UseRwSignal<T> {
|
||||
type Value = T;
|
||||
|
||||
fn set(&self, new_value: T) {
|
||||
|
@ -133,23 +101,7 @@ impl<T> SignalSet for UseRwSignal<T> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T> SignalSetUntracked<T> for UseRwSignal<T> {
|
||||
fn set_untracked(&self, new_value: T) {
|
||||
match self {
|
||||
Self::Separate(_, s) => s.set_untracked(new_value),
|
||||
Self::Combined(s) => s.set_untracked(new_value),
|
||||
}
|
||||
}
|
||||
|
||||
fn try_set_untracked(&self, new_value: T) -> Option<T> {
|
||||
match self {
|
||||
Self::Separate(_, s) => s.try_set_untracked(new_value),
|
||||
Self::Combined(s) => s.try_set_untracked(new_value),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> SignalUpdate for UseRwSignal<T> {
|
||||
impl<T> Update for UseRwSignal<T> {
|
||||
type Value = T;
|
||||
|
||||
fn update(&self, f: impl FnOnce(&mut T)) {
|
||||
|
@ -165,4 +117,18 @@ impl<T> SignalUpdate for UseRwSignal<T> {
|
|||
Self::Combined(s) => s.try_update(f),
|
||||
}
|
||||
}
|
||||
|
||||
fn maybe_update(&self, fun: impl FnOnce(&mut Self::Value) -> bool) {
|
||||
match self {
|
||||
Self::Separate(_, s) => s.maybe_update(fun),
|
||||
Self::Combined(s) => s.maybe_update(fun),
|
||||
}
|
||||
}
|
||||
|
||||
fn try_maybe_update<U>(&self, fun: impl FnOnce(&mut Self::Value) -> (bool, U)) -> Option<U> {
|
||||
match self {
|
||||
Self::Separate(_, s) => s.try_maybe_update(fun),
|
||||
Self::Combined(s) => s.try_maybe_update(fun),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
use crate::core::{ElementMaybeSignal, ElementsMaybeSignal};
|
||||
use cfg_if::cfg_if;
|
||||
use default_struct_builder::DefaultBuilder;
|
||||
use leptos::prelude::diagnostics::SpecialNonReactiveZone;
|
||||
|
||||
cfg_if! { if #[cfg(not(feature = "ssr"))] {
|
||||
use leptos::prelude::*;
|
||||
|
@ -115,6 +114,7 @@ where
|
|||
|
||||
#[cfg(not(feature = "ssr"))]
|
||||
{
|
||||
use leptos::prelude::diagnostics::SpecialNonReactiveZone;
|
||||
let OnClickOutsideOptions {
|
||||
ignore,
|
||||
capture,
|
||||
|
|
|
@ -15,7 +15,7 @@ pub fn use_local_storage<T, C>(
|
|||
key: impl AsRef<str>,
|
||||
) -> (Signal<T>, WriteSignal<T>, impl Fn() + Clone)
|
||||
where
|
||||
T: Clone + Default + PartialEq,
|
||||
T: Clone + Default + PartialEq + Send + Sync,
|
||||
C: StringCodec<T> + Default,
|
||||
{
|
||||
use_storage_with_options(
|
||||
|
@ -31,7 +31,7 @@ pub fn use_local_storage_with_options<T, C>(
|
|||
options: UseStorageOptions<T, C>,
|
||||
) -> (Signal<T>, WriteSignal<T>, impl Fn() + Clone)
|
||||
where
|
||||
T: Clone + PartialEq,
|
||||
T: Clone + PartialEq + Send + Sync,
|
||||
C: StringCodec<T> + Default,
|
||||
{
|
||||
use_storage_with_options(StorageType::Local, key, options)
|
||||
|
|
|
@ -15,7 +15,7 @@ pub fn use_session_storage<T, C>(
|
|||
key: impl AsRef<str>,
|
||||
) -> (Signal<T>, WriteSignal<T>, impl Fn() + Clone)
|
||||
where
|
||||
T: Clone + Default + PartialEq,
|
||||
T: Clone + Default + PartialEq + Send + Sync,
|
||||
C: StringCodec<T> + Default,
|
||||
{
|
||||
use_storage_with_options(
|
||||
|
@ -31,7 +31,7 @@ pub fn use_session_storage_with_options<T, C>(
|
|||
options: UseStorageOptions<T, C>,
|
||||
) -> (Signal<T>, WriteSignal<T>, impl Fn() + Clone)
|
||||
where
|
||||
T: Clone + PartialEq,
|
||||
T: Clone + PartialEq + Send + Sync,
|
||||
C: StringCodec<T> + Default,
|
||||
{
|
||||
use_storage_with_options(StorageType::Session, key, options)
|
||||
|
|
|
@ -5,7 +5,7 @@ use crate::{
|
|||
use cfg_if::cfg_if;
|
||||
use leptos::prelude::wrappers::read::Signal;
|
||||
use leptos::prelude::*;
|
||||
use std::rc::Rc;
|
||||
use std::sync::Arc;
|
||||
use thiserror::Error;
|
||||
use wasm_bindgen::JsValue;
|
||||
|
||||
|
@ -93,7 +93,7 @@ pub fn use_storage<T, C>(
|
|||
key: impl AsRef<str>,
|
||||
) -> (Signal<T>, WriteSignal<T>, impl Fn() + Clone)
|
||||
where
|
||||
T: Default + Clone + PartialEq,
|
||||
T: Default + Clone + PartialEq + Send + Sync,
|
||||
C: StringCodec<T> + Default,
|
||||
{
|
||||
use_storage_with_options::<T, C>(storage_type, key, UseStorageOptions::default())
|
||||
|
@ -106,7 +106,7 @@ pub fn use_storage_with_options<T, C>(
|
|||
options: UseStorageOptions<T, C>,
|
||||
) -> (Signal<T>, WriteSignal<T>, impl Fn() + Clone)
|
||||
where
|
||||
T: Clone + PartialEq,
|
||||
T: Clone + PartialEq + Send + Sync,
|
||||
C: StringCodec<T> + Default,
|
||||
{
|
||||
let UseStorageOptions {
|
||||
|
@ -216,10 +216,10 @@ where
|
|||
fetch_from_storage();
|
||||
|
||||
// Fires when storage needs to be fetched
|
||||
let notify = create_trigger();
|
||||
let notify = Trigger::new();
|
||||
|
||||
// Refetch from storage. Keeps track of how many times we've been notified. Does not increment for calls to set_data
|
||||
let notify_id = create_memo::<usize>(move |prev| {
|
||||
let notify_id = Memo::<usize>::new(move |prev| {
|
||||
notify.track();
|
||||
match prev {
|
||||
None => 1, // Avoid async fetch of initial value
|
||||
|
@ -334,7 +334,7 @@ pub struct UseStorageOptions<T: 'static, C: StringCodec<T>> {
|
|||
// Translates to and from UTF-16 strings
|
||||
codec: C,
|
||||
// Callback for when an error occurs
|
||||
on_error: Rc<dyn Fn(UseStorageError<C::Error>)>,
|
||||
on_error: Arc<dyn Fn(UseStorageError<C::Error>)>,
|
||||
// Whether to continuously listen to changes from browser storage
|
||||
listen_to_storage_changes: bool,
|
||||
// Initial value to use when the storage key is not set
|
||||
|
@ -346,7 +346,7 @@ pub struct UseStorageOptions<T: 'static, C: StringCodec<T>> {
|
|||
/// Calls the on_error callback with the given error. Removes the error from the Result to avoid double error handling.
|
||||
#[cfg(not(feature = "ssr"))]
|
||||
fn handle_error<T, Err>(
|
||||
on_error: &Rc<dyn Fn(UseStorageError<Err>)>,
|
||||
on_error: &Arc<dyn Fn(UseStorageError<Err>)>,
|
||||
result: Result<T, UseStorageError<Err>>,
|
||||
) -> Result<T, ()> {
|
||||
result.map_err(|err| (on_error)(err))
|
||||
|
@ -356,7 +356,7 @@ impl<T: Default, C: StringCodec<T> + Default> Default for UseStorageOptions<T, C
|
|||
fn default() -> Self {
|
||||
Self {
|
||||
codec: C::default(),
|
||||
on_error: Rc::new(|_err| ()),
|
||||
on_error: Arc::new(|_err| ()),
|
||||
listen_to_storage_changes: true,
|
||||
initial_value: MaybeRwSignal::default(),
|
||||
filter: FilterOptions::default(),
|
||||
|
@ -376,7 +376,7 @@ impl<T: Default, C: StringCodec<T>> UseStorageOptions<T, C> {
|
|||
/// Optional callback whenever an error occurs.
|
||||
pub fn on_error(self, on_error: impl Fn(UseStorageError<C::Error>) + 'static) -> Self {
|
||||
Self {
|
||||
on_error: Rc::new(on_error),
|
||||
on_error: Arc::new(on_error),
|
||||
..self
|
||||
}
|
||||
}
|
||||
|
|
|
@ -283,7 +283,7 @@ where
|
|||
on_changed(mode, Rc::new(default_on_changed.clone()));
|
||||
};
|
||||
|
||||
create_effect({
|
||||
Effect::new({
|
||||
let on_changed = on_changed.clone();
|
||||
|
||||
move |_| {
|
||||
|
|
|
@ -628,7 +628,7 @@ fn read_cookies_string(
|
|||
|
||||
let _ = ssr_cookies_header_getter;
|
||||
|
||||
let js_value: wasm_bindgen::JsValue = leptos::document().into();
|
||||
let js_value: wasm_bindgen::JsValue = document().into();
|
||||
let document: web_sys::HtmlDocument = js_value.unchecked_into();
|
||||
cookies = Some(document.cookie().unwrap_or_default());
|
||||
}
|
||||
|
|
|
@ -35,13 +35,13 @@ pub fn use_cycle_list<T, L>(
|
|||
list: L,
|
||||
) -> UseCycleListReturn<
|
||||
T,
|
||||
impl Fn(usize) -> T + Clone,
|
||||
impl Fn(usize) -> T + Clone + Send + Sync,
|
||||
impl Fn() + Clone,
|
||||
impl Fn() + Clone,
|
||||
impl Fn(i64) -> T + Clone,
|
||||
>
|
||||
where
|
||||
T: Clone + PartialEq + 'static,
|
||||
T: Clone + PartialEq + Send + Sync + 'static,
|
||||
L: Into<MaybeSignal<Vec<T>>>,
|
||||
{
|
||||
use_cycle_list_with_options(list, UseCycleListOptions::default())
|
||||
|
@ -58,7 +58,7 @@ pub fn use_cycle_list_with_options<T, L>(
|
|||
impl Fn(i64) -> T + Clone,
|
||||
>
|
||||
where
|
||||
T: Clone + PartialEq + 'static,
|
||||
T: Clone + PartialEq + Send + Sync + 'static,
|
||||
L: Into<MaybeSignal<Vec<T>>>,
|
||||
{
|
||||
let UseCycleListOptions {
|
||||
|
|
|
@ -1,8 +1,7 @@
|
|||
pub use crate::utils::DebounceOptions;
|
||||
use crate::utils::{create_filter_wrapper, create_filter_wrapper_with_arg, debounce_filter};
|
||||
use leptos::MaybeSignal;
|
||||
use std::cell::RefCell;
|
||||
use std::rc::Rc;
|
||||
use leptos::prelude::MaybeSignal;
|
||||
use std::sync::{Arc, Mutex};
|
||||
|
||||
/// Debounce execution of a function.
|
||||
///
|
||||
|
@ -77,7 +76,7 @@ use std::rc::Rc;
|
|||
pub fn use_debounce_fn<F, R>(
|
||||
func: F,
|
||||
ms: impl Into<MaybeSignal<f64>> + 'static,
|
||||
) -> impl Fn() -> Rc<RefCell<Option<R>>> + Clone
|
||||
) -> impl Fn() -> Arc<Mutex<Option<R>>> + Clone
|
||||
where
|
||||
F: Fn() -> R + Clone + 'static,
|
||||
R: 'static,
|
||||
|
@ -90,19 +89,19 @@ pub fn use_debounce_fn_with_options<F, R>(
|
|||
func: F,
|
||||
ms: impl Into<MaybeSignal<f64>> + 'static,
|
||||
options: DebounceOptions,
|
||||
) -> impl Fn() -> Rc<RefCell<Option<R>>> + Clone
|
||||
) -> impl Fn() -> Arc<Mutex<Option<R>>> + Clone
|
||||
where
|
||||
F: Fn() -> R + Clone + 'static,
|
||||
R: 'static,
|
||||
{
|
||||
create_filter_wrapper(Rc::new(debounce_filter(ms, options)), func)
|
||||
create_filter_wrapper(Arc::new(debounce_filter(ms, options)), func)
|
||||
}
|
||||
|
||||
/// Version of [`use_debounce_fn`] with an argument for the debounced function. See the docs for [`use_debounce_fn`] for how to use.
|
||||
pub fn use_debounce_fn_with_arg<F, Arg, R>(
|
||||
func: F,
|
||||
ms: impl Into<MaybeSignal<f64>> + 'static,
|
||||
) -> impl Fn(Arg) -> Rc<RefCell<Option<R>>> + Clone
|
||||
) -> impl Fn(Arg) -> Arc<Mutex<Option<R>>> + Clone
|
||||
where
|
||||
F: Fn(Arg) -> R + Clone + 'static,
|
||||
Arg: Clone + 'static,
|
||||
|
@ -116,11 +115,11 @@ pub fn use_debounce_fn_with_arg_and_options<F, Arg, R>(
|
|||
func: F,
|
||||
ms: impl Into<MaybeSignal<f64>> + 'static,
|
||||
options: DebounceOptions,
|
||||
) -> impl Fn(Arg) -> Rc<RefCell<Option<R>>> + Clone
|
||||
) -> impl Fn(Arg) -> Arc<Mutex<Option<R>>> + Clone
|
||||
where
|
||||
F: Fn(Arg) -> R + Clone + 'static,
|
||||
Arg: Clone + 'static,
|
||||
R: 'static,
|
||||
{
|
||||
create_filter_wrapper_with_arg(Rc::new(debounce_filter(ms, options)), func)
|
||||
create_filter_wrapper_with_arg(Arc::new(debounce_filter(ms, options)), func)
|
||||
}
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
use cfg_if::cfg_if;
|
||||
use leptos::prelude::wrappers::read::Signal;
|
||||
use leptos::prelude::*;
|
||||
|
||||
/// Reactive [DeviceOrientationEvent](https://developer.mozilla.org/en-US/docs/Web/API/DeviceOrientationEvent).
|
||||
/// Provide web developers with information from the physical orientation of
|
||||
|
@ -42,6 +41,7 @@ pub fn use_device_orientation() -> UseDeviceOrientationReturn {
|
|||
let beta = || None;
|
||||
let gamma = || None;
|
||||
} else {
|
||||
use leptos::prelude::*;
|
||||
use crate::{use_event_listener_with_options, UseEventListenerOptions, use_supported, js};
|
||||
use leptos::ev::deviceorientation;
|
||||
|
||||
|
@ -67,7 +67,7 @@ pub fn use_device_orientation() -> UseDeviceOrientationReturn {
|
|||
.once(false),
|
||||
);
|
||||
|
||||
leptos::on_cleanup(cleanup);
|
||||
on_cleanup(cleanup);
|
||||
}
|
||||
}}
|
||||
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
use cfg_if::cfg_if;
|
||||
use leptos::prelude::wrappers::read::Signal;
|
||||
use leptos::prelude::*;
|
||||
|
||||
/// Reactive [`window.devicePixelRatio`](https://developer.mozilla.org/en-US/docs/Web/API/Window/devicePixelRatio)
|
||||
///
|
||||
|
@ -31,15 +30,17 @@ use leptos::prelude::*;
|
|||
/// On the server this function returns a Signal that is always `1.0`.
|
||||
pub fn use_device_pixel_ratio() -> Signal<f64> {
|
||||
cfg_if! { if #[cfg(feature = "ssr")] {
|
||||
use leptos::prelude::*;
|
||||
let pixel_ratio = Signal::derive(|| 1.0);
|
||||
} else {
|
||||
use crate::{use_event_listener_with_options, UseEventListenerOptions};
|
||||
use leptos::prelude::*;
|
||||
use leptos::ev::change;
|
||||
|
||||
let initial_pixel_ratio = window().device_pixel_ratio();
|
||||
let (pixel_ratio, set_pixel_ratio) = signal(initial_pixel_ratio);
|
||||
|
||||
create_effect(move |_| {
|
||||
Effect::new(move |_| {
|
||||
let media = window().match_media(
|
||||
&format!("(resolution: {}dppx)", pixel_ratio.get())
|
||||
).unwrap();
|
||||
|
|
|
@ -3,6 +3,7 @@ use cfg_if::cfg_if;
|
|||
use default_struct_builder::DefaultBuilder;
|
||||
use leptos::prelude::wrappers::read::Signal;
|
||||
use leptos::prelude::*;
|
||||
use send_wrapper::SendWrapper;
|
||||
use wasm_bindgen::{JsCast, JsValue};
|
||||
|
||||
/// Reactive [`mediaDevices.getDisplayMedia`](https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/getDisplayMedia) streaming.
|
||||
|
@ -55,7 +56,8 @@ pub fn use_display_media_with_options(
|
|||
|
||||
let (enabled, set_enabled) = enabled.into_signal();
|
||||
|
||||
let (stream, set_stream) = signal(None::<Result<web_sys::MediaStream, JsValue>>);
|
||||
let (stream, set_stream) =
|
||||
signal(None::<Result<SendWrapper<web_sys::MediaStream>, SendWrapper<JsValue>>>);
|
||||
|
||||
let _start = move || async move {
|
||||
cfg_if! { if #[cfg(not(feature = "ssr"))] {
|
||||
|
@ -63,7 +65,10 @@ pub fn use_display_media_with_options(
|
|||
return;
|
||||
}
|
||||
|
||||
let stream = create_media(audio).await;
|
||||
let stream = create_media(audio)
|
||||
.await
|
||||
.map(SendWrapper::new)
|
||||
.map_err(SendWrapper::new);
|
||||
|
||||
set_stream.update(|s| *s = Some(stream));
|
||||
} else {
|
||||
|
@ -83,7 +88,7 @@ pub fn use_display_media_with_options(
|
|||
|
||||
let start = move || {
|
||||
cfg_if! { if #[cfg(not(feature = "ssr"))] {
|
||||
spawn_local(async move {
|
||||
leptos::spawn::spawn_local(async move {
|
||||
_start().await;
|
||||
stream.with_untracked(move |stream| {
|
||||
if let Some(Ok(_)) = stream {
|
||||
|
@ -103,7 +108,7 @@ pub fn use_display_media_with_options(
|
|||
move || enabled.get(),
|
||||
move |enabled, _, _| {
|
||||
if *enabled {
|
||||
spawn_local(async move {
|
||||
leptos::spawn::spawn_local(async move {
|
||||
_start().await;
|
||||
});
|
||||
} else {
|
||||
|
@ -176,7 +181,7 @@ where
|
|||
/// Initially this is `None` until `start` resolved successfully.
|
||||
/// In case the stream couldn't be started, for example because the user didn't grant permission,
|
||||
/// this has the value `Some(Err(...))`.
|
||||
pub stream: Signal<Option<Result<web_sys::MediaStream, JsValue>>>,
|
||||
pub stream: Signal<Option<Result<SendWrapper<web_sys::MediaStream>, SendWrapper<JsValue>>>>,
|
||||
|
||||
/// Starts the screen streaming. Triggers the ask for permission if not already granted.
|
||||
pub start: StartFn,
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
use crate::core::ElementMaybeSignal;
|
||||
use cfg_if::cfg_if;
|
||||
use default_struct_builder::DefaultBuilder;
|
||||
use leptos::prelude::diagnostics::SpecialNonReactiveZone;
|
||||
use leptos::prelude::wrappers::read::Signal;
|
||||
use leptos::prelude::*;
|
||||
use std::fmt::{Debug, Formatter};
|
||||
|
@ -78,6 +77,7 @@ where
|
|||
|
||||
#[cfg(not(feature = "ssr"))]
|
||||
{
|
||||
use leptos::prelude::diagnostics::SpecialNonReactiveZone;
|
||||
let UseDropZoneOptions {
|
||||
on_drop,
|
||||
on_enter,
|
||||
|
|
|
@ -2,7 +2,6 @@ use crate::core::ElementMaybeSignal;
|
|||
use cfg_if::cfg_if;
|
||||
use default_struct_builder::DefaultBuilder;
|
||||
use leptos::ev::EventDescriptor;
|
||||
use leptos::prelude::diagnostics::SpecialNonReactiveZone;
|
||||
|
||||
cfg_if! { if #[cfg(not(feature = "ssr"))] {
|
||||
use crate::{watch_with_options, WatchOptions};
|
||||
|
@ -120,6 +119,8 @@ where
|
|||
|
||||
#[cfg(not(feature = "ssr"))]
|
||||
{
|
||||
use leptos::prelude::diagnostics::SpecialNonReactiveZone;
|
||||
use send_wrapper::SendWrapper;
|
||||
let event_name = event.name();
|
||||
let closure_js = Closure::wrap(Box::new(move |e| {
|
||||
#[cfg(debug_assertions)]
|
||||
|
@ -187,7 +188,8 @@ where
|
|||
cleanup_prev_element();
|
||||
};
|
||||
|
||||
on_cleanup(stop.clone());
|
||||
let cleanup_stop = SendWrapper::new(stop.clone());
|
||||
on_cleanup(move || cleanup_stop());
|
||||
|
||||
stop
|
||||
}
|
||||
|
|
|
@ -5,9 +5,10 @@ use default_struct_builder::DefaultBuilder;
|
|||
use leptos::prelude::diagnostics::SpecialNonReactiveZone;
|
||||
use leptos::prelude::wrappers::read::Signal;
|
||||
use leptos::prelude::*;
|
||||
use send_wrapper::SendWrapper;
|
||||
use std::cell::Cell;
|
||||
use std::marker::PhantomData;
|
||||
use std::rc::Rc;
|
||||
use std::sync::Arc;
|
||||
use std::time::Duration;
|
||||
use thiserror::Error;
|
||||
|
||||
|
@ -114,8 +115,9 @@ pub fn use_event_source<T, C>(
|
|||
url: &str,
|
||||
) -> UseEventSourceReturn<T, C::Error, impl Fn() + Clone + 'static, impl Fn() + Clone + 'static>
|
||||
where
|
||||
T: Clone + PartialEq + 'static,
|
||||
T: Clone + PartialEq + Send + Sync + 'static,
|
||||
C: StringCodec<T> + Default,
|
||||
C::Error: Send + Sync,
|
||||
{
|
||||
use_event_source_with_options(url, UseEventSourceOptions::<T, C>::default())
|
||||
}
|
||||
|
@ -126,8 +128,9 @@ pub fn use_event_source_with_options<T, C>(
|
|||
options: UseEventSourceOptions<T, C>,
|
||||
) -> UseEventSourceReturn<T, C::Error, impl Fn() + Clone + 'static, impl Fn() + Clone + 'static>
|
||||
where
|
||||
T: Clone + PartialEq + 'static,
|
||||
T: Clone + PartialEq + Send + Sync + 'static,
|
||||
C: StringCodec<T> + Default,
|
||||
C::Error: Send + Sync,
|
||||
{
|
||||
let UseEventSourceOptions {
|
||||
codec,
|
||||
|
@ -142,14 +145,14 @@ where
|
|||
|
||||
let url = url.to_owned();
|
||||
|
||||
let (event, set_event) = signal(None::<web_sys::Event>);
|
||||
let (event, set_event) = signal(None::<SendWrapper<web_sys::Event>>);
|
||||
let (data, set_data) = signal(None::<T>);
|
||||
let (ready_state, set_ready_state) = signal(ConnectionReadyState::Closed);
|
||||
let (event_source, set_event_source) = signal(None::<web_sys::EventSource>);
|
||||
let (event_source, set_event_source) = signal(None::<SendWrapper<web_sys::EventSource>>);
|
||||
let (error, set_error) = signal(None::<UseEventSourceError<C::Error>>);
|
||||
|
||||
let explicitly_closed = Rc::new(Cell::new(false));
|
||||
let retried = Rc::new(Cell::new(0));
|
||||
let explicitly_closed = Arc::new(Cell::new(false));
|
||||
let retried = Arc::new(Cell::new(0));
|
||||
|
||||
let set_data_from_string = move |data_string: Option<String>| {
|
||||
if let Some(data_string) = data_string {
|
||||
|
@ -161,7 +164,7 @@ where
|
|||
};
|
||||
|
||||
let close = {
|
||||
let explicitly_closed = Rc::clone(&explicitly_closed);
|
||||
let explicitly_closed = Arc::clone(&explicitly_closed);
|
||||
|
||||
move || {
|
||||
if let Some(event_source) = event_source.get_untracked() {
|
||||
|
@ -173,11 +176,11 @@ where
|
|||
}
|
||||
};
|
||||
|
||||
let init = StoredValue::new(None::<Rc<dyn Fn()>>);
|
||||
let init = StoredValue::new(None::<Arc<dyn Fn() + Send + Sync>>);
|
||||
|
||||
init.set_value(Some(Rc::new({
|
||||
let explicitly_closed = Rc::clone(&explicitly_closed);
|
||||
let retried = Rc::clone(&retried);
|
||||
init.set_value(Some(Arc::new({
|
||||
let explicitly_closed = Arc::clone(&explicitly_closed);
|
||||
let retried = Arc::clone(&retried);
|
||||
|
||||
move || {
|
||||
use wasm_bindgen::prelude::*;
|
||||
|
@ -194,7 +197,7 @@ where
|
|||
|
||||
set_ready_state.set(ConnectionReadyState::Connecting);
|
||||
|
||||
set_event_source.set(Some(es.clone()));
|
||||
set_event_source.set(Some(SendWrapper::new(es.clone())));
|
||||
|
||||
let on_open = Closure::wrap(Box::new(move |_: web_sys::Event| {
|
||||
set_ready_state.set(ConnectionReadyState::Open);
|
||||
|
@ -204,14 +207,14 @@ where
|
|||
on_open.forget();
|
||||
|
||||
let on_error = Closure::wrap(Box::new({
|
||||
let explicitly_closed = Rc::clone(&explicitly_closed);
|
||||
let retried = Rc::clone(&retried);
|
||||
let on_failed = Rc::clone(&on_failed);
|
||||
let explicitly_closed = Arc::clone(&explicitly_closed);
|
||||
let retried = Arc::clone(&retried);
|
||||
let on_failed = Arc::clone(&on_failed);
|
||||
let es = es.clone();
|
||||
|
||||
move |e: web_sys::Event| {
|
||||
set_ready_state.set(ConnectionReadyState::Closed);
|
||||
set_error.set(Some(UseEventSourceError::Event(e)));
|
||||
set_error.set(Some(UseEventSourceError::Event(SendWrapper::new(e))));
|
||||
|
||||
// only reconnect if EventSource isn't reconnecting by itself
|
||||
// this is the case when the connection is closed (readyState is 2)
|
||||
|
@ -273,8 +276,8 @@ where
|
|||
{
|
||||
open = {
|
||||
let close = close.clone();
|
||||
let explicitly_closed = Rc::clone(&explicitly_closed);
|
||||
let retried = Rc::clone(&retried);
|
||||
let explicitly_closed = Arc::clone(&explicitly_closed);
|
||||
let retried = Arc::clone(&retried);
|
||||
|
||||
move || {
|
||||
close();
|
||||
|
@ -326,7 +329,7 @@ where
|
|||
reconnect_interval: u64,
|
||||
|
||||
/// On maximum retry times reached.
|
||||
on_failed: Rc<dyn Fn()>,
|
||||
on_failed: Arc<dyn Fn()>,
|
||||
|
||||
/// If `true` the `EventSource` connection will immediately be opened when calling this function.
|
||||
/// If `false` you have to manually call the `open` function.
|
||||
|
@ -349,7 +352,7 @@ impl<T, C: StringCodec<T> + Default> Default for UseEventSourceOptions<T, C> {
|
|||
codec: C::default(),
|
||||
reconnect_limit: 3,
|
||||
reconnect_interval: 3000,
|
||||
on_failed: Rc::new(|| {}),
|
||||
on_failed: Arc::new(|| {}),
|
||||
immediate: true,
|
||||
named_events: vec![],
|
||||
with_credentials: false,
|
||||
|
@ -361,8 +364,8 @@ impl<T, C: StringCodec<T> + Default> Default for UseEventSourceOptions<T, C> {
|
|||
/// Return type of [`use_event_source`].
|
||||
pub struct UseEventSourceReturn<T, Err, OpenFn, CloseFn>
|
||||
where
|
||||
Err: 'static,
|
||||
T: Clone + 'static,
|
||||
Err: Send + Sync + 'static,
|
||||
T: Clone + Send + Sync + 'static,
|
||||
OpenFn: Fn() + Clone + 'static,
|
||||
CloseFn: Fn() + Clone + 'static,
|
||||
{
|
||||
|
@ -373,7 +376,7 @@ where
|
|||
pub ready_state: Signal<ConnectionReadyState>,
|
||||
|
||||
/// The latest named event
|
||||
pub event: Signal<Option<web_sys::Event>>,
|
||||
pub event: Signal<Option<SendWrapper<web_sys::Event>>>,
|
||||
|
||||
/// The current error
|
||||
pub error: Signal<Option<UseEventSourceError<Err>>>,
|
||||
|
@ -386,13 +389,13 @@ where
|
|||
pub close: CloseFn,
|
||||
|
||||
/// The `EventSource` instance
|
||||
pub event_source: Signal<Option<web_sys::EventSource>>,
|
||||
pub event_source: Signal<Option<SendWrapper<web_sys::EventSource>>>,
|
||||
}
|
||||
|
||||
#[derive(Error, Debug)]
|
||||
pub enum UseEventSourceError<Err> {
|
||||
#[error("Error event: {0:?}")]
|
||||
Event(web_sys::Event),
|
||||
Event(SendWrapper<web_sys::Event>),
|
||||
|
||||
#[error("Error decoding value")]
|
||||
Deserialize(Err),
|
||||
|
|
|
@ -2,6 +2,7 @@ use cfg_if::cfg_if;
|
|||
use default_struct_builder::DefaultBuilder;
|
||||
use leptos::prelude::wrappers::read::Signal;
|
||||
use leptos::prelude::*;
|
||||
use send_wrapper::SendWrapper;
|
||||
|
||||
/// Reactive [Geolocation API](https://developer.mozilla.org/en-US/docs/Web/API/Geolocation_API).
|
||||
/// It allows the user to provide their location to web applications if they so desire. For privacy reasons,
|
||||
|
@ -43,8 +44,8 @@ pub fn use_geolocation_with_options(
|
|||
options: UseGeolocationOptions,
|
||||
) -> UseGeolocationReturn<impl Fn() + Clone, impl Fn() + Clone> {
|
||||
let (located_at, set_located_at) = signal(None::<f64>);
|
||||
let (error, set_error) = signal(None::<web_sys::PositionError>);
|
||||
let (coords, set_coords) = signal(None::<web_sys::Coordinates>);
|
||||
let (error, set_error) = signal(None::<SendWrapper<web_sys::PositionError>>);
|
||||
let (coords, set_coords) = signal(None::<SendWrapper<web_sys::Coordinates>>);
|
||||
|
||||
cfg_if! { if #[cfg(feature = "ssr")] {
|
||||
let resume = || ();
|
||||
|
@ -56,24 +57,23 @@ pub fn use_geolocation_with_options(
|
|||
let _ = set_coords;
|
||||
} else {
|
||||
use crate::use_window;
|
||||
use std::cell::Cell;
|
||||
use std::rc::Rc;
|
||||
use wasm_bindgen::prelude::*;
|
||||
use std::sync::{Arc, Mutex};
|
||||
|
||||
let update_position = move |position: web_sys::Position| {
|
||||
set_located_at.set(Some(position.timestamp()));
|
||||
set_coords.set(Some(position.coords()));
|
||||
set_coords.set(Some(SendWrapper::new(position.coords())));
|
||||
set_error.set(None);
|
||||
};
|
||||
|
||||
let on_error = move |err: web_sys::PositionError| {
|
||||
set_error.set(Some(err));
|
||||
set_error.set(Some(SendWrapper::new(err)));
|
||||
};
|
||||
|
||||
let watch_handle = Rc::new(Cell::new(None::<i32>));
|
||||
let watch_handle = Arc::new(Mutex::new(None::<i32>));
|
||||
|
||||
let resume = {
|
||||
let watch_handle = Rc::clone(&watch_handle);
|
||||
let watch_handle = Arc::clone(&watch_handle);
|
||||
let position_options = options.as_position_options();
|
||||
|
||||
move || {
|
||||
|
@ -85,15 +85,14 @@ pub fn use_geolocation_with_options(
|
|||
let on_error =
|
||||
Closure::wrap(Box::new(on_error) as Box<dyn Fn(web_sys::PositionError)>);
|
||||
|
||||
watch_handle.replace(
|
||||
*watch_handle.lock().unwrap() =
|
||||
geolocation
|
||||
.watch_position_with_error_callback_and_options(
|
||||
update_position.as_ref().unchecked_ref(),
|
||||
Some(on_error.as_ref().unchecked_ref()),
|
||||
&position_options,
|
||||
)
|
||||
.ok(),
|
||||
);
|
||||
.ok();
|
||||
|
||||
update_position.forget();
|
||||
on_error.forget();
|
||||
|
@ -107,12 +106,12 @@ pub fn use_geolocation_with_options(
|
|||
}
|
||||
|
||||
let pause = {
|
||||
let watch_handle = Rc::clone(&watch_handle);
|
||||
let watch_handle = Arc::clone(&watch_handle);
|
||||
|
||||
move || {
|
||||
let navigator = use_window().navigator();
|
||||
if let Some(navigator) = navigator {
|
||||
if let Some(handle) = watch_handle.take() {
|
||||
if let Some(handle) = *watch_handle.lock().unwrap() {
|
||||
if let Ok(geolocation) = navigator.geolocation() {
|
||||
geolocation.clear_watch(handle);
|
||||
}
|
||||
|
@ -204,13 +203,13 @@ where
|
|||
{
|
||||
/// The coordinates of the current device like latitude and longitude.
|
||||
/// See [`GeolocationCoordinates`](https://developer.mozilla.org/en-US/docs/Web/API/GeolocationCoordinates)..
|
||||
pub coords: Signal<Option<web_sys::Coordinates>>,
|
||||
pub coords: Signal<Option<SendWrapper<web_sys::Coordinates>>>,
|
||||
|
||||
/// The timestamp of the current coordinates.
|
||||
pub located_at: Signal<Option<f64>>,
|
||||
|
||||
/// The last error received from `navigator.geolocation`.
|
||||
pub error: Signal<Option<web_sys::PositionError>>,
|
||||
pub error: Signal<Option<SendWrapper<web_sys::PositionError>>>,
|
||||
|
||||
/// Resume the geolocation watch.
|
||||
pub resume: ResumeFn,
|
||||
|
|
|
@ -158,7 +158,7 @@ where
|
|||
set_loading.set(true);
|
||||
|
||||
let measure = measure.clone();
|
||||
spawn_local(async move {
|
||||
leptos::spawn::spawn_local(async move {
|
||||
#[cfg(debug_assertions)]
|
||||
let zone = SpecialNonReactiveZone::enter();
|
||||
|
||||
|
|
|
@ -102,7 +102,7 @@ where
|
|||
let closure_js = Closure::<dyn FnMut(js_sys::Array, web_sys::IntersectionObserver)>::new(
|
||||
move |entries: js_sys::Array, observer| {
|
||||
#[cfg(debug_assertions)]
|
||||
let _z = SpecialNonReactiveZone::enter();
|
||||
let _z = leptos::prelude::diagnostics::SpecialNonReactiveZone::enter();
|
||||
|
||||
callback(
|
||||
entries
|
||||
|
|
|
@ -91,7 +91,7 @@ pub fn use_media_query(query: impl Into<MaybeSignal<String>>) -> Signal<bool> {
|
|||
listener.replace(Rc::new(move |_| update()) as Rc<dyn Fn(web_sys::Event)>);
|
||||
}
|
||||
|
||||
create_effect(move |_| update());
|
||||
Effect::new(move |_| update());
|
||||
|
||||
on_cleanup(cleanup);
|
||||
}}
|
||||
|
|
|
@ -46,12 +46,12 @@ pub fn use_permission(permission_name: &str) -> Signal<PermissionState> {
|
|||
}
|
||||
};
|
||||
|
||||
spawn_local({
|
||||
leptos::spawn::spawn_local({
|
||||
let permission_name = permission_name.to_owned();
|
||||
|
||||
async move {
|
||||
if let Ok(status) = query_permission(permission_name).await {
|
||||
let _ = use_event_listener(status.clone(), ev::change, {
|
||||
let _ = use_event_listener(status.clone(), leptos::ev::change, {
|
||||
let on_change = on_change.clone();
|
||||
move |_| on_change()
|
||||
});
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
use crate::use_media_query;
|
||||
use leptos::prelude::wrappers::read::Signal;
|
||||
use leptos::prelude::*;
|
||||
|
||||
/// Reactive [dark theme preference](https://developer.mozilla.org/en-US/docs/Web/CSS/@media/prefers-color-scheme).
|
||||
|
|
|
@ -138,7 +138,8 @@ pub fn use_raf_fn_with_options(
|
|||
resume();
|
||||
}
|
||||
|
||||
on_cleanup(pause.clone());
|
||||
let pause_cleanup = send_wrapper::SendWrapper::new(pause.clone());
|
||||
on_cleanup(move || pause_cleanup());
|
||||
|
||||
Pausable {
|
||||
resume,
|
||||
|
|
|
@ -11,6 +11,7 @@ use crate::use_event_listener::use_event_listener_with_options;
|
|||
use crate::{
|
||||
use_debounce_fn_with_arg, use_throttle_fn_with_arg_and_options, ThrottleOptions,
|
||||
};
|
||||
use leptos::ev;
|
||||
use leptos::ev::scrollend;
|
||||
use wasm_bindgen::JsCast;
|
||||
|
||||
|
@ -202,13 +203,13 @@ where
|
|||
|
||||
let (is_scrolling, set_is_scrolling) = signal(false);
|
||||
|
||||
let arrived_state = create_rw_signal(Directions {
|
||||
let arrived_state = RwSignal::new(Directions {
|
||||
left: true,
|
||||
right: false,
|
||||
top: true,
|
||||
bottom: false,
|
||||
});
|
||||
let directions = create_rw_signal(Directions {
|
||||
let directions = RwSignal::new(Directions {
|
||||
left: false,
|
||||
right: false,
|
||||
top: false,
|
||||
|
|
|
@ -3,7 +3,8 @@ use leptos::prelude::actions::Action;
|
|||
use leptos::prelude::diagnostics::SpecialNonReactiveZone;
|
||||
use leptos::prelude::wrappers::read::Signal;
|
||||
use leptos::prelude::*;
|
||||
use std::rc::Rc;
|
||||
use send_wrapper::SendWrapper;
|
||||
use std::sync::Arc;
|
||||
use wasm_bindgen::{prelude::Closure, JsCast, JsValue};
|
||||
use web_sys::ServiceWorkerRegistration;
|
||||
|
||||
|
@ -73,20 +74,21 @@ pub fn use_service_worker_with_options(
|
|||
create_or_update_registration.dispatch(ServiceWorkerScriptUrl(options.script_url.to_string()));
|
||||
|
||||
// And parse the result into individual signals.
|
||||
let registration: Signal<Result<ServiceWorkerRegistration, ServiceWorkerRegistrationError>> =
|
||||
Signal::derive(move || {
|
||||
let a = get_registration.value().get();
|
||||
let b = create_or_update_registration.value().get();
|
||||
// We only dispatch create_or_update_registration once.
|
||||
// Whenever we manually re-fetched the registration, the result of that has precedence!
|
||||
match a {
|
||||
Some(res) => res.map_err(ServiceWorkerRegistrationError::Js),
|
||||
None => match b {
|
||||
Some(res) => res.map_err(ServiceWorkerRegistrationError::Js),
|
||||
None => Err(ServiceWorkerRegistrationError::NeverQueried),
|
||||
},
|
||||
}
|
||||
});
|
||||
let registration: Signal<
|
||||
Result<SendWrapper<ServiceWorkerRegistration>, ServiceWorkerRegistrationError>,
|
||||
> = Signal::derive(move || {
|
||||
let a = get_registration.value().get();
|
||||
let b = create_or_update_registration.value().get();
|
||||
// We only dispatch create_or_update_registration once.
|
||||
// Whenever we manually re-fetched the registration, the result of that has precedence!
|
||||
match a {
|
||||
Some(res) => res.map_err(ServiceWorkerRegistrationError::Js),
|
||||
None => match b {
|
||||
Some(res) => res.map_err(|e| ServiceWorkerRegistrationError::Js(e)),
|
||||
None => Err(ServiceWorkerRegistrationError::NeverQueried),
|
||||
},
|
||||
}
|
||||
});
|
||||
|
||||
let fetch_registration = Closure::wrap(Box::new(move |_event: JsValue| {
|
||||
get_registration.dispatch(());
|
||||
|
@ -182,7 +184,7 @@ pub struct UseServiceWorkerOptions {
|
|||
|
||||
/// What should happen when a new service worker was activated?
|
||||
/// The default implementation reloads the current page.
|
||||
on_controller_change: Rc<dyn Fn()>,
|
||||
on_controller_change: Arc<dyn Fn()>,
|
||||
}
|
||||
|
||||
impl Default for UseServiceWorkerOptions {
|
||||
|
@ -190,7 +192,7 @@ impl Default for UseServiceWorkerOptions {
|
|||
Self {
|
||||
script_url: "service-worker.js".into(),
|
||||
skip_waiting_message: "skipWaiting".into(),
|
||||
on_controller_change: Rc::new(move || {
|
||||
on_controller_change: Arc::new(move || {
|
||||
use std::ops::Deref;
|
||||
if let Some(window) = use_window().deref() {
|
||||
if let Err(err) = window.location().reload() {
|
||||
|
@ -211,7 +213,8 @@ where
|
|||
SkipFn: Fn() + Clone,
|
||||
{
|
||||
/// The current registration state.
|
||||
pub registration: Signal<Result<ServiceWorkerRegistration, ServiceWorkerRegistrationError>>,
|
||||
pub registration:
|
||||
Signal<Result<SendWrapper<ServiceWorkerRegistration>, ServiceWorkerRegistrationError>>,
|
||||
|
||||
/// Whether a SW is currently installing.
|
||||
pub installing: Signal<bool>,
|
||||
|
@ -234,29 +237,37 @@ struct ServiceWorkerScriptUrl(pub String);
|
|||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum ServiceWorkerRegistrationError {
|
||||
Js(JsValue),
|
||||
Js(SendWrapper<JsValue>),
|
||||
NeverQueried,
|
||||
}
|
||||
|
||||
/// A leptos action which asynchronously checks for ServiceWorker updates, given an existing ServiceWorkerRegistration.
|
||||
fn create_action_update(
|
||||
) -> Action<ServiceWorkerRegistration, Result<ServiceWorkerRegistration, JsValue>> {
|
||||
Action::new(move |registration: &ServiceWorkerRegistration| {
|
||||
let registration = registration.clone();
|
||||
async move {
|
||||
match registration.update() {
|
||||
Ok(promise) => js_fut!(promise)
|
||||
.await
|
||||
.and_then(|ok| ok.dyn_into::<ServiceWorkerRegistration>()),
|
||||
Err(err) => Err(err),
|
||||
fn create_action_update() -> Action<
|
||||
SendWrapper<ServiceWorkerRegistration>,
|
||||
Result<SendWrapper<ServiceWorkerRegistration>, SendWrapper<JsValue>>,
|
||||
> {
|
||||
Action::new(
|
||||
move |registration: &SendWrapper<ServiceWorkerRegistration>| {
|
||||
let registration = registration.clone();
|
||||
async move {
|
||||
match registration.update() {
|
||||
Ok(promise) => js_fut!(promise)
|
||||
.await
|
||||
.and_then(|ok| ok.dyn_into::<ServiceWorkerRegistration>())
|
||||
.map(SendWrapper::new)
|
||||
.map_err(SendWrapper::new),
|
||||
Err(err) => Err(err),
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
/// A leptos action which asynchronously creates or updates and than retrieves the ServiceWorkerRegistration.
|
||||
fn create_action_create_or_update_registration(
|
||||
) -> Action<ServiceWorkerScriptUrl, Result<ServiceWorkerRegistration, JsValue>> {
|
||||
fn create_action_create_or_update_registration() -> Action<
|
||||
ServiceWorkerScriptUrl,
|
||||
Result<SendWrapper<ServiceWorkerRegistration>, SendWrapper<JsValue>>,
|
||||
> {
|
||||
Action::new(move |script_url: &ServiceWorkerScriptUrl| {
|
||||
let script_url = script_url.0.to_owned();
|
||||
async move {
|
||||
|
@ -272,14 +283,17 @@ fn create_action_create_or_update_registration(
|
|||
}
|
||||
|
||||
/// A leptos action which asynchronously fetches the current ServiceWorkerRegistration.
|
||||
fn create_action_get_registration() -> Action<(), Result<ServiceWorkerRegistration, JsValue>> {
|
||||
fn create_action_get_registration(
|
||||
) -> Action<(), Result<SendWrapper<ServiceWorkerRegistration>, SendWrapper<JsValue>>> {
|
||||
Action::new(move |(): &()| async move {
|
||||
if let Some(navigator) = use_window().navigator() {
|
||||
js_fut!(navigator.service_worker().get_registration())
|
||||
.await
|
||||
.and_then(|ok| ok.dyn_into::<ServiceWorkerRegistration>())
|
||||
.map(SendWrapper::new)
|
||||
.map_err(SendWrapper::new)
|
||||
} else {
|
||||
Err(JsValue::from_str("no navigator"))
|
||||
Err(SendWrapper::new(JsValue::from_str("no navigator")))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
use leptos::prelude::wrappers::read::Signal;
|
||||
use leptos::prelude::*;
|
||||
|
||||
/// SSR compatibe `is_supported`
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
use crate::utils::{create_filter_wrapper, create_filter_wrapper_with_arg, throttle_filter};
|
||||
use leptos::MaybeSignal;
|
||||
use std::cell::RefCell;
|
||||
use std::rc::Rc;
|
||||
use leptos::prelude::MaybeSignal;
|
||||
use std::sync::{Arc, Mutex};
|
||||
|
||||
pub use crate::utils::ThrottleOptions;
|
||||
|
||||
|
@ -73,7 +72,7 @@ pub use crate::utils::ThrottleOptions;
|
|||
pub fn use_throttle_fn<F, R>(
|
||||
func: F,
|
||||
ms: impl Into<MaybeSignal<f64>> + 'static,
|
||||
) -> impl Fn() -> Rc<RefCell<Option<R>>> + Clone
|
||||
) -> impl Fn() -> Arc<Mutex<Option<R>>> + Clone
|
||||
where
|
||||
F: Fn() -> R + Clone + 'static,
|
||||
R: 'static,
|
||||
|
@ -86,19 +85,19 @@ pub fn use_throttle_fn_with_options<F, R>(
|
|||
func: F,
|
||||
ms: impl Into<MaybeSignal<f64>> + 'static,
|
||||
options: ThrottleOptions,
|
||||
) -> impl Fn() -> Rc<RefCell<Option<R>>> + Clone
|
||||
) -> impl Fn() -> Arc<Mutex<Option<R>>> + Clone
|
||||
where
|
||||
F: Fn() -> R + Clone + 'static,
|
||||
R: 'static,
|
||||
{
|
||||
create_filter_wrapper(Rc::new(throttle_filter(ms, options)), func)
|
||||
create_filter_wrapper(Arc::new(throttle_filter(ms, options)), func)
|
||||
}
|
||||
|
||||
/// Version of [`use_throttle_fn`] with an argument for the throttled function. See the docs for [`use_throttle_fn`] for how to use.
|
||||
pub fn use_throttle_fn_with_arg<F, Arg, R>(
|
||||
func: F,
|
||||
ms: impl Into<MaybeSignal<f64>> + 'static,
|
||||
) -> impl Fn(Arg) -> Rc<RefCell<Option<R>>> + Clone
|
||||
) -> impl Fn(Arg) -> Arc<Mutex<Option<R>>> + Clone
|
||||
where
|
||||
F: Fn(Arg) -> R + Clone + 'static,
|
||||
Arg: Clone + 'static,
|
||||
|
@ -112,11 +111,11 @@ pub fn use_throttle_fn_with_arg_and_options<F, Arg, R>(
|
|||
func: F,
|
||||
ms: impl Into<MaybeSignal<f64>> + 'static,
|
||||
options: ThrottleOptions,
|
||||
) -> impl Fn(Arg) -> Rc<RefCell<Option<R>>> + Clone
|
||||
) -> impl Fn(Arg) -> Arc<Mutex<Option<R>>> + Clone
|
||||
where
|
||||
F: Fn(Arg) -> R + Clone + 'static,
|
||||
Arg: Clone + 'static,
|
||||
R: 'static,
|
||||
{
|
||||
create_filter_wrapper_with_arg(Rc::new(throttle_filter(ms, options)), func)
|
||||
create_filter_wrapper_with_arg(Arc::new(throttle_filter(ms, options)), func)
|
||||
}
|
||||
|
|
|
@ -2,9 +2,8 @@ use leptos::leptos_dom::helpers::TimeoutHandle;
|
|||
use leptos::prelude::diagnostics::SpecialNonReactiveZone;
|
||||
use leptos::prelude::wrappers::read::Signal;
|
||||
use leptos::prelude::*;
|
||||
use std::cell::Cell;
|
||||
use std::marker::PhantomData;
|
||||
use std::rc::Rc;
|
||||
use std::sync::{Arc, Mutex};
|
||||
use std::time::Duration;
|
||||
|
||||
/// Wrapper for `setTimeout` with controls.
|
||||
|
@ -46,13 +45,14 @@ where
|
|||
|
||||
let (is_pending, set_pending) = signal(false);
|
||||
|
||||
let timer = Rc::new(Cell::new(None::<TimeoutHandle>));
|
||||
let timer = Arc::new(Mutex::new(None::<TimeoutHandle>));
|
||||
|
||||
let clear = {
|
||||
let timer = Rc::clone(&timer);
|
||||
let timer = Arc::clone(&timer);
|
||||
|
||||
move || {
|
||||
if let Some(timer) = timer.take() {
|
||||
let timer = timer.lock().unwrap();
|
||||
if let Some(timer) = *timer {
|
||||
timer.clear();
|
||||
}
|
||||
}
|
||||
|
@ -68,7 +68,7 @@ where
|
|||
};
|
||||
|
||||
let start = {
|
||||
let timer = Rc::clone(&timer);
|
||||
let timer = Arc::clone(&timer);
|
||||
let callback = callback.clone();
|
||||
|
||||
move |arg: Arg| {
|
||||
|
@ -76,12 +76,12 @@ where
|
|||
|
||||
let handle = set_timeout_with_handle(
|
||||
{
|
||||
let timer = Rc::clone(&timer);
|
||||
let timer = Arc::clone(&timer);
|
||||
let callback = callback.clone();
|
||||
|
||||
move || {
|
||||
set_pending.set(false);
|
||||
timer.set(None);
|
||||
*timer.lock().unwrap() = None;
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
let _z = SpecialNonReactiveZone::enter();
|
||||
|
@ -93,7 +93,7 @@ where
|
|||
)
|
||||
.ok();
|
||||
|
||||
timer.set(handle);
|
||||
*timer.lock().unwrap() = handle;
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -1,9 +1,8 @@
|
|||
use crate::{use_supported, use_window};
|
||||
use cfg_if::cfg_if;
|
||||
use default_struct_builder::DefaultBuilder;
|
||||
use leptos::prelude::diagnostics::SpecialNonReactiveZone;
|
||||
use leptos::prelude::wrappers::read::Signal;
|
||||
use leptos::prelude::*;
|
||||
use leptos::prelude::{wrappers::read::Signal, *};
|
||||
use send_wrapper::SendWrapper;
|
||||
use std::rc::Rc;
|
||||
|
||||
/// Reactive [Notification API](https://developer.mozilla.org/en-US/docs/Web/API/Notification).
|
||||
|
@ -53,7 +52,7 @@ pub fn use_web_notification_with_options(
|
|||
) -> UseWebNotificationReturn<impl Fn(ShowOptions) + Clone, impl Fn() + Clone> {
|
||||
let is_supported = use_supported(browser_supports_notifications);
|
||||
|
||||
let (notification, set_notification) = signal(None::<web_sys::Notification>);
|
||||
let (notification, set_notification) = signal(None::<SendWrapper<web_sys::Notification>>);
|
||||
|
||||
let (permission, set_permission) = signal(NotificationPermission::default());
|
||||
|
||||
|
@ -65,6 +64,7 @@ pub fn use_web_notification_with_options(
|
|||
let show = move |_: ShowOptions| ();
|
||||
let close = move || ();
|
||||
} else {
|
||||
use leptos::{spawn::spawn_local, prelude::diagnostics::SpecialNonReactiveZone};
|
||||
use crate::use_event_listener;
|
||||
use leptos::ev::visibilitychange;
|
||||
use wasm_bindgen::closure::Closure;
|
||||
|
@ -462,7 +462,7 @@ where
|
|||
CloseFn: Fn() + Clone,
|
||||
{
|
||||
pub is_supported: Signal<bool>,
|
||||
pub notification: Signal<Option<web_sys::Notification>>,
|
||||
pub notification: Signal<Option<SendWrapper<web_sys::Notification>>>,
|
||||
pub show: ShowFn,
|
||||
pub close: CloseFn,
|
||||
pub permission: Signal<NotificationPermission>,
|
||||
|
|
|
@ -2,8 +2,8 @@
|
|||
|
||||
use cfg_if::cfg_if;
|
||||
use leptos::{leptos_dom::helpers::TimeoutHandle, prelude::*};
|
||||
use std::cell::Cell;
|
||||
use std::rc::Rc;
|
||||
use send_wrapper::SendWrapper;
|
||||
use std::sync::{atomic::AtomicBool, Arc};
|
||||
use std::time::Duration;
|
||||
|
||||
use crate::core::ConnectionReadyState;
|
||||
|
@ -100,16 +100,16 @@ use web_sys::{BinaryType, CloseEvent, Event, MessageEvent, WebSocket};
|
|||
///
|
||||
/// ```
|
||||
/// # use leptos::prelude::*;
|
||||
/// use std::rc::Rc;
|
||||
/// use std::sync::Arc;
|
||||
///
|
||||
/// #[derive(Clone)]
|
||||
/// pub struct WebsocketContext {
|
||||
/// pub message: Signal<Option<String>>,
|
||||
/// send: Rc<dyn Fn(&str)>, // use Rc to make it easily cloneable
|
||||
/// send: Arc<dyn Fn(&str)>, // use Arc to make it easily cloneable
|
||||
/// }
|
||||
///
|
||||
/// impl WebsocketContext {
|
||||
/// pub fn new(message: Signal<Option<String>>, send: Rc<dyn Fn(&str)>) -> Self {
|
||||
/// pub fn new(message: Signal<Option<String>>, send: Arc<dyn Fn(&str)>) -> Self {
|
||||
/// Self {
|
||||
/// message,
|
||||
/// send,
|
||||
|
@ -129,15 +129,15 @@ use web_sys::{BinaryType, CloseEvent, Event, MessageEvent, WebSocket};
|
|||
/// ```
|
||||
/// # use leptos::prelude::*;
|
||||
/// # use leptos_use::{use_websocket, UseWebsocketReturn};
|
||||
/// # use std::rc::Rc;
|
||||
/// # use std::sync::Arc;
|
||||
/// # #[derive(Clone)]
|
||||
/// # pub struct WebsocketContext {
|
||||
/// # pub message: Signal<Option<String>>,
|
||||
/// # send: Rc<dyn Fn(&str)>,
|
||||
/// # send: Arc<dyn Fn(&str)>,
|
||||
/// # }
|
||||
/// #
|
||||
/// # impl WebsocketContext {
|
||||
/// # pub fn new(message: Signal<Option<String>>, send: Rc<dyn Fn(&str)>) -> Self {
|
||||
/// # pub fn new(message: Signal<Option<String>>, send: Arc<dyn Fn(&str)>) -> Self {
|
||||
/// # Self {
|
||||
/// # message,
|
||||
/// # send,
|
||||
|
@ -153,7 +153,7 @@ use web_sys::{BinaryType, CloseEvent, Event, MessageEvent, WebSocket};
|
|||
/// ..
|
||||
/// } = use_websocket("ws:://some.websocket.io");
|
||||
///
|
||||
/// provide_context(WebsocketContext::new(message, Rc::new(send.clone())));
|
||||
/// provide_context(WebsocketContext::new(message, Arc::new(send.clone())));
|
||||
/// #
|
||||
/// # view! {}
|
||||
/// # }
|
||||
|
@ -164,11 +164,11 @@ use web_sys::{BinaryType, CloseEvent, Event, MessageEvent, WebSocket};
|
|||
/// ```
|
||||
/// # use leptos::prelude::*;
|
||||
/// # use leptos_use::{use_websocket, UseWebsocketReturn};
|
||||
/// # use std::rc::Rc;
|
||||
/// # use std::sync::Arc;
|
||||
/// # #[derive(Clone)]
|
||||
/// # pub struct WebsocketContext {
|
||||
/// # pub message: Signal<Option<String>>,
|
||||
/// # send: Rc<dyn Fn(&str)>,
|
||||
/// # send: Arc<dyn Fn(&str)>,
|
||||
/// # }
|
||||
/// #
|
||||
/// # impl WebsocketContext {
|
||||
|
@ -228,26 +228,27 @@ pub fn use_websocket_with_options(
|
|||
let (ready_state, set_ready_state) = signal(ConnectionReadyState::Closed);
|
||||
let (message, set_message) = signal(None);
|
||||
let (message_bytes, set_message_bytes) = signal(None);
|
||||
let ws_ref: StoredValue<Option<WebSocket>> = StoredValue::new(None);
|
||||
let ws_ref: StoredValue<Option<SendWrapper<WebSocket>>> = StoredValue::new(None);
|
||||
|
||||
let reconnect_timer_ref: StoredValue<Option<TimeoutHandle>> = StoredValue::new(None);
|
||||
|
||||
let reconnect_times_ref: StoredValue<u64> = StoredValue::new(0);
|
||||
|
||||
let unmounted = Rc::new(Cell::new(false));
|
||||
let unmounted = Arc::new(AtomicBool::new(false));
|
||||
|
||||
let connect_ref: StoredValue<Option<Rc<dyn Fn()>>> = StoredValue::new(None);
|
||||
let connect_ref: StoredValue<Option<Arc<dyn Fn() + Send + Sync>>> = StoredValue::new(None);
|
||||
|
||||
#[cfg(not(feature = "ssr"))]
|
||||
{
|
||||
let reconnect_ref: StoredValue<Option<Rc<dyn Fn()>>> = StoredValue::new(None);
|
||||
let reconnect_ref: StoredValue<Option<Arc<dyn Fn() + Send + Sync>>> =
|
||||
StoredValue::new(None);
|
||||
reconnect_ref.set_value({
|
||||
let ws = ws_ref.get_value();
|
||||
Some(Rc::new(move || {
|
||||
Some(Arc::new(move || {
|
||||
if reconnect_times_ref.get_value() < reconnect_limit
|
||||
&& ws
|
||||
.clone()
|
||||
.map_or(false, |ws: WebSocket| ws.ready_state() != WebSocket::OPEN)
|
||||
&& ws.clone().map_or(false, |ws: SendWrapper<WebSocket>| {
|
||||
ws.ready_state() != WebSocket::OPEN
|
||||
})
|
||||
{
|
||||
reconnect_timer_ref.set_value(
|
||||
set_timeout_with_handle(
|
||||
|
@ -267,9 +268,9 @@ pub fn use_websocket_with_options(
|
|||
|
||||
connect_ref.set_value({
|
||||
let ws = ws_ref.get_value();
|
||||
let unmounted = Rc::clone(&unmounted);
|
||||
let unmounted = Arc::clone(&unmounted);
|
||||
|
||||
Some(Rc::new(move || {
|
||||
Some(Arc::new(move || {
|
||||
reconnect_timer_ref.set_value(None);
|
||||
|
||||
if let Some(web_socket) = &ws {
|
||||
|
@ -294,8 +295,8 @@ pub fn use_websocket_with_options(
|
|||
|
||||
// onopen handler
|
||||
{
|
||||
let unmounted = Rc::clone(&unmounted);
|
||||
let on_open = Rc::clone(&on_open);
|
||||
let unmounted = Arc::clone(&unmounted);
|
||||
let on_open = Arc::clone(&on_open);
|
||||
|
||||
let onopen_closure = Closure::wrap(Box::new(move |e: Event| {
|
||||
if unmounted.get() {
|
||||
|
@ -303,7 +304,7 @@ pub fn use_websocket_with_options(
|
|||
}
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
let zone = SpecialNonReactiveZone::enter();
|
||||
let zone = diagnostics::SpecialNonReactiveZone::enter();
|
||||
|
||||
on_open(e);
|
||||
|
||||
|
@ -320,9 +321,9 @@ pub fn use_websocket_with_options(
|
|||
|
||||
// onmessage handler
|
||||
{
|
||||
let unmounted = Rc::clone(&unmounted);
|
||||
let on_message = Rc::clone(&on_message);
|
||||
let on_message_bytes = Rc::clone(&on_message_bytes);
|
||||
let unmounted = Arc::clone(&unmounted);
|
||||
let on_message = Arc::clone(&on_message);
|
||||
let on_message_bytes = Arc::clone(&on_message_bytes);
|
||||
|
||||
let onmessage_closure = Closure::wrap(Box::new(move |e: MessageEvent| {
|
||||
if unmounted.get() {
|
||||
|
@ -342,7 +343,7 @@ pub fn use_websocket_with_options(
|
|||
let txt = String::from(&txt);
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
let zone = SpecialNonReactiveZone::enter();
|
||||
let zone = diagnostics::SpecialNonReactiveZone::enter();
|
||||
|
||||
on_message(txt.clone());
|
||||
|
||||
|
@ -358,7 +359,7 @@ pub fn use_websocket_with_options(
|
|||
let array = array.to_vec();
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
let zone = SpecialNonReactiveZone::enter();
|
||||
let zone = diagnostics::SpecialNonReactiveZone::enter();
|
||||
|
||||
on_message_bytes(array.clone());
|
||||
|
||||
|
@ -376,8 +377,8 @@ pub fn use_websocket_with_options(
|
|||
|
||||
// onerror handler
|
||||
{
|
||||
let unmounted = Rc::clone(&unmounted);
|
||||
let on_error = Rc::clone(&on_error);
|
||||
let unmounted = Arc::clone(&unmounted);
|
||||
let on_error = Arc::clone(&on_error);
|
||||
|
||||
let onerror_closure = Closure::wrap(Box::new(move |e: Event| {
|
||||
if unmounted.get() {
|
||||
|
@ -389,7 +390,7 @@ pub fn use_websocket_with_options(
|
|||
}
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
let zone = SpecialNonReactiveZone::enter();
|
||||
let zone = diagnostics::SpecialNonReactiveZone::enter();
|
||||
|
||||
on_error(e);
|
||||
|
||||
|
@ -405,8 +406,8 @@ pub fn use_websocket_with_options(
|
|||
|
||||
// onclose handler
|
||||
{
|
||||
let unmounted = Rc::clone(&unmounted);
|
||||
let on_close = Rc::clone(&on_close);
|
||||
let unmounted = Arc::clone(&unmounted);
|
||||
let on_close = Arc::clone(&on_close);
|
||||
|
||||
let onclose_closure = Closure::wrap(Box::new(move |e: CloseEvent| {
|
||||
if unmounted.get() {
|
||||
|
@ -418,7 +419,7 @@ pub fn use_websocket_with_options(
|
|||
}
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
let zone = SpecialNonReactiveZone::enter();
|
||||
let zone = diagnostics::SpecialNonReactiveZone::enter();
|
||||
|
||||
on_close(e);
|
||||
|
||||
|
@ -486,7 +487,7 @@ pub fn use_websocket_with_options(
|
|||
|
||||
// clean up (unmount)
|
||||
on_cleanup(move || {
|
||||
unmounted.set(true);
|
||||
unmounted.store(true, std::sync::atomic::Ordering::Relaxed);
|
||||
close();
|
||||
});
|
||||
|
||||
|
@ -506,15 +507,15 @@ pub fn use_websocket_with_options(
|
|||
#[derive(DefaultBuilder)]
|
||||
pub struct UseWebSocketOptions {
|
||||
/// `WebSocket` connect callback.
|
||||
on_open: Rc<dyn Fn(Event)>,
|
||||
on_open: Arc<dyn Fn(Event) + Send + Sync>,
|
||||
/// `WebSocket` message callback for text.
|
||||
on_message: Rc<dyn Fn(String)>,
|
||||
on_message: Arc<dyn Fn(String) + Send + Sync>,
|
||||
/// `WebSocket` message callback for binary.
|
||||
on_message_bytes: Rc<dyn Fn(Vec<u8>)>,
|
||||
on_message_bytes: Arc<dyn Fn(Vec<u8>) + Send + Sync>,
|
||||
/// `WebSocket` error callback.
|
||||
on_error: Rc<dyn Fn(Event)>,
|
||||
on_error: Arc<dyn Fn(Event) + Send + Sync>,
|
||||
/// `WebSocket` close callback.
|
||||
on_close: Rc<dyn Fn(CloseEvent)>,
|
||||
on_close: Arc<dyn Fn(CloseEvent) + Send + Sync>,
|
||||
/// Retry times. Defaults to 3.
|
||||
reconnect_limit: u64,
|
||||
/// Retry interval in ms. Defaults to 3000.
|
||||
|
@ -530,11 +531,11 @@ pub struct UseWebSocketOptions {
|
|||
impl Default for UseWebSocketOptions {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
on_open: Rc::new(|_| {}),
|
||||
on_message: Rc::new(|_| {}),
|
||||
on_message_bytes: Rc::new(|_| {}),
|
||||
on_error: Rc::new(|_| {}),
|
||||
on_close: Rc::new(|_| {}),
|
||||
on_open: Arc::new(|_| {}),
|
||||
on_message: Arc::new(|_| {}),
|
||||
on_message_bytes: Arc::new(|_| {}),
|
||||
on_error: Arc::new(|_| {}),
|
||||
on_close: Arc::new(|_| {}),
|
||||
reconnect_limit: 3,
|
||||
reconnect_interval: 3000,
|
||||
immediate: true,
|
||||
|
@ -559,7 +560,7 @@ where
|
|||
/// Latest binary message received from `WebSocket`.
|
||||
pub message_bytes: Signal<Option<Vec<u8>>>,
|
||||
/// The `WebSocket` instance.
|
||||
pub ws: Option<WebSocket>,
|
||||
pub ws: Option<SendWrapper<WebSocket>>,
|
||||
/// Opens the `WebSocket` connection
|
||||
pub open: OpenFn,
|
||||
/// Closes the `WebSocket` connection
|
||||
|
|
|
@ -5,8 +5,7 @@ use default_struct_builder::DefaultBuilder;
|
|||
use leptos::leptos_dom::helpers::TimeoutHandle;
|
||||
use leptos::prelude::diagnostics::SpecialNonReactiveZone;
|
||||
use leptos::prelude::*;
|
||||
use std::cell::{Cell, RefCell};
|
||||
use std::rc::Rc;
|
||||
use std::sync::{Arc, Mutex};
|
||||
use std::time::Duration;
|
||||
|
||||
#[derive(Copy, Clone, DefaultBuilder, Default)]
|
||||
|
@ -20,23 +19,24 @@ pub struct DebounceOptions {
|
|||
pub fn debounce_filter<R>(
|
||||
ms: impl Into<MaybeSignal<f64>>,
|
||||
options: DebounceOptions,
|
||||
) -> impl Fn(Rc<dyn Fn() -> R>) -> Rc<RefCell<Option<R>>> + Clone
|
||||
) -> impl Fn(Arc<dyn Fn() -> R>) -> Arc<Mutex<Option<R>>> + Clone
|
||||
where
|
||||
R: 'static,
|
||||
{
|
||||
let timer = Rc::new(Cell::new(None::<TimeoutHandle>));
|
||||
let max_timer = Rc::new(Cell::new(None::<TimeoutHandle>));
|
||||
let last_return_value: Rc<RefCell<Option<R>>> = Rc::new(RefCell::new(None));
|
||||
let timer = Arc::new(Mutex::new(None::<TimeoutHandle>));
|
||||
let max_timer = Arc::new(Mutex::new(None::<TimeoutHandle>));
|
||||
let last_return_value: Arc<Mutex<Option<R>>> = Arc::new(Mutex::new(None));
|
||||
|
||||
let clear_timeout = move |timer: &Rc<Cell<Option<TimeoutHandle>>>| {
|
||||
if let Some(handle) = timer.get() {
|
||||
let clear_timeout = move |timer: &Arc<Mutex<Option<TimeoutHandle>>>| {
|
||||
let mut timer = timer.lock().unwrap();
|
||||
if let Some(handle) = *timer {
|
||||
handle.clear();
|
||||
timer.set(None);
|
||||
*timer = None;
|
||||
}
|
||||
};
|
||||
|
||||
on_cleanup({
|
||||
let timer = Rc::clone(&timer);
|
||||
let timer = Arc::clone(&timer);
|
||||
|
||||
move || {
|
||||
clear_timeout(&timer);
|
||||
|
@ -46,11 +46,11 @@ where
|
|||
let ms = ms.into();
|
||||
let max_wait_signal = options.max_wait;
|
||||
|
||||
move |_invoke: Rc<dyn Fn() -> R>| {
|
||||
move |_invoke: Arc<dyn Fn() -> R>| {
|
||||
let duration = ms.get_untracked();
|
||||
let max_duration = max_wait_signal.get_untracked();
|
||||
|
||||
let last_return_val = Rc::clone(&last_return_value);
|
||||
let last_return_val = Arc::clone(&last_return_value);
|
||||
let invoke = move || {
|
||||
#[cfg(debug_assertions)]
|
||||
let zone = SpecialNonReactiveZone::enter();
|
||||
|
@ -60,7 +60,7 @@ where
|
|||
#[cfg(debug_assertions)]
|
||||
drop(zone);
|
||||
|
||||
let mut val_mut = last_return_val.borrow_mut();
|
||||
let mut val_mut = last_return_val.lock().unwrap();
|
||||
*val_mut = Some(return_value);
|
||||
};
|
||||
|
||||
|
@ -70,43 +70,41 @@ where
|
|||
clear_timeout(&max_timer);
|
||||
|
||||
invoke();
|
||||
return Rc::clone(&last_return_value);
|
||||
return Arc::clone(&last_return_value);
|
||||
}
|
||||
|
||||
cfg_if! { if #[cfg(not(feature = "ssr"))] {
|
||||
// Create the max_timer. Clears the regular timer on invoke
|
||||
if let Some(max_duration) = max_duration {
|
||||
if max_timer.get().is_none() {
|
||||
let timer = Rc::clone(&timer);
|
||||
let mut max_timer = max_timer.lock().unwrap();
|
||||
|
||||
if max_timer.is_none() {
|
||||
let timer = Arc::clone(&timer);
|
||||
let invok = invoke.clone();
|
||||
max_timer.set(
|
||||
set_timeout_with_handle(
|
||||
move || {
|
||||
clear_timeout(&timer);
|
||||
invok();
|
||||
},
|
||||
Duration::from_millis(max_duration as u64),
|
||||
)
|
||||
.ok(),
|
||||
);
|
||||
*max_timer = set_timeout_with_handle(
|
||||
move || {
|
||||
clear_timeout(&timer);
|
||||
invok();
|
||||
},
|
||||
Duration::from_millis(max_duration as u64),
|
||||
)
|
||||
.ok();
|
||||
}
|
||||
}
|
||||
|
||||
let max_timer = Rc::clone(&max_timer);
|
||||
let max_timer = Arc::clone(&max_timer);
|
||||
|
||||
// Create the regular timer. Clears the max timer on invoke
|
||||
timer.set(
|
||||
set_timeout_with_handle(
|
||||
move || {
|
||||
clear_timeout(&max_timer);
|
||||
invoke();
|
||||
},
|
||||
Duration::from_millis(duration as u64),
|
||||
)
|
||||
.ok(),
|
||||
);
|
||||
*timer.lock().unwrap() = set_timeout_with_handle(
|
||||
move || {
|
||||
clear_timeout(&max_timer);
|
||||
invoke();
|
||||
},
|
||||
Duration::from_millis(duration as u64),
|
||||
)
|
||||
.ok();
|
||||
}}
|
||||
|
||||
Rc::clone(&last_return_value)
|
||||
Arc::clone(&last_return_value)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,31 +4,30 @@ mod throttle;
|
|||
pub use debounce::*;
|
||||
pub use throttle::*;
|
||||
|
||||
use leptos::MaybeSignal;
|
||||
use std::cell::RefCell;
|
||||
use std::rc::Rc;
|
||||
use leptos::prelude::MaybeSignal;
|
||||
use std::sync::{Arc, Mutex};
|
||||
|
||||
macro_rules! RcFilterFn {
|
||||
macro_rules! ArcFilterFn {
|
||||
($R:ident) => {
|
||||
Rc<dyn Fn(Rc<dyn Fn() -> $R>) -> Rc<RefCell<Option<$R>>>>
|
||||
Arc<dyn Fn(Arc<dyn Fn() -> $R>) -> Arc<Mutex<Option<$R>>>>
|
||||
}
|
||||
}
|
||||
|
||||
pub fn create_filter_wrapper<F, R>(
|
||||
filter: RcFilterFn!(R),
|
||||
filter: ArcFilterFn!(R),
|
||||
func: F,
|
||||
) -> impl Fn() -> Rc<RefCell<Option<R>>> + Clone
|
||||
) -> impl Fn() -> Arc<Mutex<Option<R>>> + Clone
|
||||
where
|
||||
F: Fn() -> R + Clone + 'static,
|
||||
R: 'static,
|
||||
{
|
||||
move || Rc::clone(&filter)(Rc::new(func.clone()))
|
||||
move || Arc::clone(&filter)(Arc::new(func.clone()))
|
||||
}
|
||||
|
||||
pub fn create_filter_wrapper_with_arg<F, Arg, R>(
|
||||
filter: RcFilterFn!(R),
|
||||
filter: ArcFilterFn!(R),
|
||||
func: F,
|
||||
) -> impl Fn(Arg) -> Rc<RefCell<Option<R>>> + Clone
|
||||
) -> impl Fn(Arg) -> Arc<Mutex<Option<R>>> + Clone
|
||||
where
|
||||
F: Fn(Arg) -> R + Clone + 'static,
|
||||
R: 'static,
|
||||
|
@ -36,7 +35,7 @@ where
|
|||
{
|
||||
move |arg: Arg| {
|
||||
let func = func.clone();
|
||||
Rc::clone(&filter)(Rc::new(move || func(arg.clone())))
|
||||
Arc::clone(&filter)(Arc::new(move || func(arg.clone())))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -70,15 +69,15 @@ impl FilterOptions {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn filter_fn<R>(&self) -> RcFilterFn!(R)
|
||||
pub fn filter_fn<R>(&self) -> ArcFilterFn!(R)
|
||||
where
|
||||
R: 'static,
|
||||
{
|
||||
match self {
|
||||
FilterOptions::Debounce { ms, options } => Rc::new(debounce_filter(*ms, *options)),
|
||||
FilterOptions::Throttle { ms, options } => Rc::new(throttle_filter(*ms, *options)),
|
||||
FilterOptions::Debounce { ms, options } => Arc::new(debounce_filter(*ms, *options)),
|
||||
FilterOptions::Throttle { ms, options } => Arc::new(throttle_filter(*ms, *options)),
|
||||
FilterOptions::None => {
|
||||
Rc::new(|invoke: Rc<dyn Fn() -> R>| Rc::new(RefCell::new(Some(invoke()))))
|
||||
Arc::new(|invoke: Arc<dyn Fn() -> R>| Arc::new(Mutex::new(Some(invoke()))))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,9 +6,8 @@ use default_struct_builder::DefaultBuilder;
|
|||
use leptos::leptos_dom::helpers::TimeoutHandle;
|
||||
use leptos::prelude::diagnostics::SpecialNonReactiveZone;
|
||||
use leptos::prelude::*;
|
||||
use std::cell::{Cell, RefCell};
|
||||
use std::cmp::max;
|
||||
use std::rc::Rc;
|
||||
use std::sync::{atomic::AtomicBool, Arc, Mutex};
|
||||
use std::time::Duration;
|
||||
|
||||
#[derive(Copy, Clone, DefaultBuilder)]
|
||||
|
@ -31,20 +30,21 @@ impl Default for ThrottleOptions {
|
|||
pub fn throttle_filter<R>(
|
||||
ms: impl Into<MaybeSignal<f64>>,
|
||||
options: ThrottleOptions,
|
||||
) -> impl Fn(Rc<dyn Fn() -> R>) -> Rc<RefCell<Option<R>>> + Clone
|
||||
) -> impl Fn(Arc<dyn Fn() -> R>) -> Arc<Mutex<Option<R>>> + Clone
|
||||
where
|
||||
R: 'static,
|
||||
{
|
||||
let last_exec = Rc::new(Cell::new(0_f64));
|
||||
let timer = Rc::new(Cell::new(None::<TimeoutHandle>));
|
||||
let is_leading = Rc::new(Cell::new(true));
|
||||
let last_return_value: Rc<RefCell<Option<R>>> = Rc::new(RefCell::new(None));
|
||||
let last_exec = Arc::new(Mutex::new(0_f64));
|
||||
let timer = Arc::new(Mutex::new(None::<TimeoutHandle>));
|
||||
let is_leading = Arc::new(AtomicBool::new(true));
|
||||
let last_return_value: Arc<Mutex<Option<R>>> = Arc::new(Mutex::new(None));
|
||||
|
||||
let t = Rc::clone(&timer);
|
||||
let t = Arc::clone(&timer);
|
||||
let clear = move || {
|
||||
if let Some(handle) = t.get() {
|
||||
let mut t = t.lock().unwrap();
|
||||
if let Some(handle) = *t {
|
||||
handle.clear();
|
||||
t.set(None);
|
||||
*t = None;
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -52,11 +52,11 @@ where
|
|||
|
||||
let ms = ms.into();
|
||||
|
||||
move |mut _invoke: Rc<dyn Fn() -> R>| {
|
||||
move |mut _invoke: Arc<dyn Fn() -> R>| {
|
||||
let duration = ms.get_untracked();
|
||||
let elapsed = now() - last_exec.get();
|
||||
let elapsed = now() - *last_exec.lock().unwrap();
|
||||
|
||||
let last_return_val = Rc::clone(&last_return_value);
|
||||
let last_return_val = Arc::clone(&last_return_value);
|
||||
let invoke = move || {
|
||||
#[cfg(debug_assertions)]
|
||||
let zone = SpecialNonReactiveZone::enter();
|
||||
|
@ -66,7 +66,7 @@ where
|
|||
#[cfg(debug_assertions)]
|
||||
drop(zone);
|
||||
|
||||
let mut val_mut = last_return_val.borrow_mut();
|
||||
let mut val_mut = last_return_val.lock().unwrap();
|
||||
*val_mut = Some(return_value);
|
||||
};
|
||||
|
||||
|
@ -74,50 +74,51 @@ where
|
|||
clear();
|
||||
|
||||
if duration <= 0.0 {
|
||||
last_exec.set(now());
|
||||
*last_exec.lock().unwrap() = now();
|
||||
invoke();
|
||||
return Rc::clone(&last_return_value);
|
||||
return Arc::clone(&last_return_value);
|
||||
}
|
||||
|
||||
if elapsed > duration && (options.leading || !is_leading.get()) {
|
||||
last_exec.set(now());
|
||||
if elapsed > duration
|
||||
&& (options.leading || !is_leading.load(std::sync::atomic::Ordering::Relaxed))
|
||||
{
|
||||
*last_exec.lock().unwrap() = now();
|
||||
invoke();
|
||||
} else if options.trailing {
|
||||
cfg_if! { if #[cfg(not(feature = "ssr"))] {
|
||||
let last_exec = Rc::clone(&last_exec);
|
||||
let is_leading = Rc::clone(&is_leading);
|
||||
timer.set(
|
||||
let last_exec = Arc::clone(&last_exec);
|
||||
let is_leading = Arc::clone(&is_leading);
|
||||
*timer.lock().unwrap() =
|
||||
set_timeout_with_handle(
|
||||
move || {
|
||||
last_exec.set(now());
|
||||
is_leading.set(true);
|
||||
*last_exec.lock().unwrap() = now();
|
||||
is_leading.store(true, std::sync::atomic::Ordering::Relaxed);
|
||||
invoke();
|
||||
clear();
|
||||
},
|
||||
Duration::from_millis(max(0, (duration - elapsed) as u64)),
|
||||
)
|
||||
.ok(),
|
||||
);
|
||||
.ok();
|
||||
}}
|
||||
}
|
||||
|
||||
cfg_if! { if #[cfg(not(feature = "ssr"))] {
|
||||
if !options.leading && timer.get().is_none() {
|
||||
let is_leading = Rc::clone(&is_leading);
|
||||
timer.set(
|
||||
set_timeout_with_handle(
|
||||
let mut timer = timer.lock().unwrap();
|
||||
|
||||
if !options.leading && timer.is_none() {
|
||||
let is_leading = Arc::clone(&is_leading);
|
||||
*timer = set_timeout_with_handle(
|
||||
move || {
|
||||
is_leading.set(true);
|
||||
is_leading.store(true, std::sync::atomic::Ordering::Relaxed);
|
||||
},
|
||||
Duration::from_millis(duration as u64),
|
||||
)
|
||||
.ok(),
|
||||
);
|
||||
.ok();
|
||||
}
|
||||
}}
|
||||
|
||||
is_leading.set(false);
|
||||
is_leading.store(false, std::sync::atomic::Ordering::Relaxed);
|
||||
|
||||
Rc::clone(&last_return_value)
|
||||
Arc::clone(&last_return_value)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use crate::filter_builder_methods;
|
||||
use crate::utils::{create_filter_wrapper, DebounceOptions, FilterOptions, ThrottleOptions};
|
||||
use default_struct_builder::DefaultBuilder;
|
||||
use leptos::prelude::*;
|
||||
use leptos::prelude::{diagnostics::SpecialNonReactiveZone, *};
|
||||
use std::cell::RefCell;
|
||||
use std::rc::Rc;
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue