mirror of
https://github.com/adoyle0/leptos-use.git
synced 2025-01-23 17:09:21 -05:00
Completed MVP port
This commit is contained in:
parent
9866ac6231
commit
c414022b23
24 changed files with 263 additions and 188 deletions
|
@ -171,7 +171,7 @@ where
|
||||||
let _ = target;
|
let _ = target;
|
||||||
Self::Static(None)
|
Self::Static(None)
|
||||||
} else {
|
} else {
|
||||||
Self::Static(document().query_selector(target).unwrap_or_default())
|
Self::Static(document().query_selector(target).unwrap_or_default().map(SendWrapper::new))
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -197,7 +197,7 @@ macro_rules! impl_from_signal_string {
|
||||||
Self::Dynamic(Signal::derive(|| None))
|
Self::Dynamic(Signal::derive(|| None))
|
||||||
} else {
|
} else {
|
||||||
Self::Dynamic(
|
Self::Dynamic(
|
||||||
Signal::derive(move || document().query_selector(&signal.get()).unwrap_or_default()),
|
Signal::derive(move || document().query_selector(&signal.get()).unwrap_or_default().map(SendWrapper::new)),
|
||||||
)
|
)
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
@ -212,8 +212,8 @@ impl_from_signal_string!(Memo<String>);
|
||||||
|
|
||||||
impl_from_signal_string!(Signal<&str>);
|
impl_from_signal_string!(Signal<&str>);
|
||||||
impl_from_signal_string!(ReadSignal<&str>);
|
impl_from_signal_string!(ReadSignal<&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 ///////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
|
|
@ -156,7 +156,7 @@ where
|
||||||
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() {
|
||||||
let node = node_list.get(i).expect("checked the range");
|
let node = node_list.get(i).expect("checked the range");
|
||||||
list.push(Some(node));
|
list.push(Some(SendWrapper::new(node)));
|
||||||
}
|
}
|
||||||
|
|
||||||
Self::Static(list)
|
Self::Static(list)
|
||||||
|
|
|
@ -68,7 +68,7 @@ mod use_preferred_dark;
|
||||||
mod use_raf_fn;
|
mod use_raf_fn;
|
||||||
mod use_resize_observer;
|
mod use_resize_observer;
|
||||||
mod use_scroll;
|
mod use_scroll;
|
||||||
mod use_service_worker;
|
// mod use_service_worker;
|
||||||
mod use_sorted;
|
mod use_sorted;
|
||||||
mod use_supported;
|
mod use_supported;
|
||||||
mod use_throttle_fn;
|
mod use_throttle_fn;
|
||||||
|
@ -134,7 +134,7 @@ pub use use_preferred_dark::*;
|
||||||
pub use use_raf_fn::*;
|
pub use use_raf_fn::*;
|
||||||
pub use use_resize_observer::*;
|
pub use use_resize_observer::*;
|
||||||
pub use use_scroll::*;
|
pub use use_scroll::*;
|
||||||
pub use use_service_worker::*;
|
// pub use use_service_worker::*;
|
||||||
pub use use_sorted::*;
|
pub use use_sorted::*;
|
||||||
pub use use_supported::*;
|
pub use use_supported::*;
|
||||||
pub use use_throttle_fn::*;
|
pub use use_throttle_fn::*;
|
||||||
|
|
|
@ -149,7 +149,7 @@ where
|
||||||
let ignore = ignore.get_untracked();
|
let ignore = ignore.get_untracked();
|
||||||
|
|
||||||
ignore.into_iter().flatten().any(|element| {
|
ignore.into_iter().flatten().any(|element| {
|
||||||
let element: web_sys::EventTarget = element.into();
|
let element: web_sys::EventTarget = element.take().into();
|
||||||
|
|
||||||
event_target::<web_sys::EventTarget>(event) == element
|
event_target::<web_sys::EventTarget>(event) == element
|
||||||
|| event.composed_path().includes(element.as_ref(), 0)
|
|| event.composed_path().includes(element.as_ref(), 0)
|
||||||
|
|
|
@ -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;
|
||||||
|
@ -202,7 +203,7 @@ where
|
||||||
// Get storage API
|
// Get storage API
|
||||||
let storage = storage_type
|
let storage = storage_type
|
||||||
.into_storage()
|
.into_storage()
|
||||||
.map_err(UseStorageError::StorageNotAvailable)
|
.map_err(|e| UseStorageError::StorageNotAvailable(SendWrapper::new(e)))
|
||||||
.and_then(|s| s.ok_or(UseStorageError::StorageReturnedNone));
|
.and_then(|s| s.ok_or(UseStorageError::StorageReturnedNone));
|
||||||
let storage = handle_error(&on_error, storage);
|
let storage = handle_error(&on_error, storage);
|
||||||
|
|
||||||
|
@ -226,7 +227,7 @@ where
|
||||||
)
|
)
|
||||||
.expect("failed to create custom storage event"),
|
.expect("failed to create custom storage event"),
|
||||||
)
|
)
|
||||||
.map_err(UseStorageError::NotifyItemChangedFailed);
|
.map_err(|e| UseStorageError::NotifyItemChangedFailed(SendWrapper::new(e)));
|
||||||
let _ = handle_error(&on_error, result);
|
let _ = handle_error(&on_error, result);
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -238,14 +239,14 @@ 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| {
|
||||||
// Get directly from storage
|
// Get directly from storage
|
||||||
let result = storage
|
let result = storage
|
||||||
.get_item(&key)
|
.get_item(&key)
|
||||||
.map_err(UseStorageError::GetItemFailed);
|
.map_err(|e| UseStorageError::GetItemFailed(SendWrapper::new(e)));
|
||||||
handle_error(&on_error, result)
|
handle_error(&on_error, result)
|
||||||
})
|
})
|
||||||
.unwrap_or_default() // Drop handled Err(())
|
.unwrap_or_default() // Drop handled Err(())
|
||||||
|
@ -270,14 +271,18 @@ 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(move |prev| {
|
let notify_id = Memo::<usize>::new({
|
||||||
|
let notify = notify.clone();
|
||||||
|
let fetch_from_storage = fetch_from_storage.clone();
|
||||||
|
|
||||||
|
move |prev| {
|
||||||
notify.track();
|
notify.track();
|
||||||
match prev {
|
match prev {
|
||||||
None => 1, // Avoid async fetch of initial value
|
None => 1, // Avoid async fetch of initial value
|
||||||
|
@ -286,6 +291,7 @@ where
|
||||||
prev + 1
|
prev + 1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Set item on internal (non-event) page changes to the data signal
|
// Set item on internal (non-event) page changes to the data signal
|
||||||
|
@ -308,9 +314,9 @@ where
|
||||||
.map_err(|e| UseStorageError::ItemCodecError(CodecError::Encode(e)))
|
.map_err(|e| UseStorageError::ItemCodecError(CodecError::Encode(e)))
|
||||||
.and_then(|enc_value| {
|
.and_then(|enc_value| {
|
||||||
// Set storage -- sends a global event
|
// Set storage -- sends a global event
|
||||||
storage
|
storage.set_item(&key, &enc_value).map_err(|e| {
|
||||||
.set_item(&key, &enc_value)
|
UseStorageError::SetItemFailed(SendWrapper::new(e))
|
||||||
.map_err(UseStorageError::SetItemFailed)
|
})
|
||||||
});
|
});
|
||||||
let result = handle_error(&on_error, result);
|
let result = handle_error(&on_error, result);
|
||||||
// Send internal storage event
|
// Send internal storage event
|
||||||
|
@ -323,31 +329,42 @@ where
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fetch initial value
|
// TODO: solve for 0.7
|
||||||
if delay_during_hydration && leptos::leptos_dom::HydrationCtx::is_hydrating() {
|
// // Fetch initial value
|
||||||
request_animation_frame(fetch_from_storage.clone());
|
// if delay_during_hydration && leptos::leptos_dom::HydrationCtx::is_hydrating() {
|
||||||
} else {
|
// request_animation_frame(fetch_from_storage.clone());
|
||||||
fetch_from_storage();
|
// } else {
|
||||||
}
|
// fetch_from_storage();
|
||||||
|
// }
|
||||||
|
request_animation_frame({
|
||||||
|
let fetch_from_storage = fetch_from_storage.clone();
|
||||||
|
#[allow(clippy::redundant_closure)]
|
||||||
|
move || 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| {
|
move |ev: web_sys::CustomEvent| {
|
||||||
if Some(check_key.clone()) == ev.detail().as_string() {
|
if Some(check_key.clone()) == ev.detail().as_string() {
|
||||||
notify.notify()
|
custom_notify.trigger()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
@ -361,9 +378,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(SendWrapper::new(e)));
|
||||||
let _ = handle_error(&on_error, result);
|
let _ = handle_error(&on_error, result);
|
||||||
notify.notify();
|
notify.trigger();
|
||||||
dispatch_storage_event();
|
dispatch_storage_event();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -377,17 +394,17 @@ where
|
||||||
#[derive(Error, Debug)]
|
#[derive(Error, Debug)]
|
||||||
pub enum UseStorageError<E, D> {
|
pub enum UseStorageError<E, D> {
|
||||||
#[error("storage not available")]
|
#[error("storage not available")]
|
||||||
StorageNotAvailable(JsValue),
|
StorageNotAvailable(SendWrapper<JsValue>),
|
||||||
#[error("storage not returned from window")]
|
#[error("storage not returned from window")]
|
||||||
StorageReturnedNone,
|
StorageReturnedNone,
|
||||||
#[error("failed to get item")]
|
#[error("failed to get item")]
|
||||||
GetItemFailed(JsValue),
|
GetItemFailed(SendWrapper<JsValue>),
|
||||||
#[error("failed to set item")]
|
#[error("failed to set item")]
|
||||||
SetItemFailed(JsValue),
|
SetItemFailed(SendWrapper<JsValue>),
|
||||||
#[error("failed to delete item")]
|
#[error("failed to delete item")]
|
||||||
RemoveItemFailed(JsValue),
|
RemoveItemFailed(SendWrapper<JsValue>),
|
||||||
#[error("failed to notify item changed")]
|
#[error("failed to notify item changed")]
|
||||||
NotifyItemChangedFailed(JsValue),
|
NotifyItemChangedFailed(SendWrapper<JsValue>),
|
||||||
#[error("failed to encode / decode item value")]
|
#[error("failed to encode / decode item value")]
|
||||||
ItemCodecError(CodecError<E, D>),
|
ItemCodecError(CodecError<E, D>),
|
||||||
}
|
}
|
||||||
|
@ -400,7 +417,7 @@ where
|
||||||
{
|
{
|
||||||
// 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
|
||||||
|
@ -418,7 +435,7 @@ 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))
|
||||||
|
@ -438,7 +455,10 @@ 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> {
|
||||||
/// 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
|
||||||
|
|
|
@ -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.
|
||||||
///
|
///
|
||||||
|
@ -143,7 +143,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,
|
||||||
{
|
{
|
||||||
use_cookie_with_options::<T, C>(cookie_name, UseCookieOptions::default())
|
use_cookie_with_options::<T, C>(cookie_name, UseCookieOptions::default())
|
||||||
}
|
}
|
||||||
|
@ -155,7 +155,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,
|
||||||
{
|
{
|
||||||
let UseCookieOptions {
|
let UseCookieOptions {
|
||||||
max_age,
|
max_age,
|
||||||
|
@ -189,7 +189,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) {
|
||||||
|
@ -229,8 +229,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();
|
||||||
|
|
||||||
|
@ -265,7 +265,7 @@ where
|
||||||
same_site,
|
same_site,
|
||||||
secure,
|
secure,
|
||||||
http_only,
|
http_only,
|
||||||
Rc::clone(&ssr_cookies_header_getter),
|
Arc::clone(&ssr_cookies_header_getter),
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -288,7 +288,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 |_| {
|
||||||
|
@ -299,7 +299,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(
|
||||||
|
@ -325,7 +325,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(
|
||||||
|
@ -467,14 +467,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> {
|
||||||
|
@ -490,7 +490,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"))]
|
||||||
|
@ -564,7 +564,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")]
|
||||||
|
@ -615,7 +615,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");
|
||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
|
@ -623,7 +623,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;
|
||||||
|
|
||||||
|
@ -646,55 +646,63 @@ 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 || {
|
||||||
elapsed.set(elapsed.get() + timeout_length);
|
let elapsed = elapsed.fetch_add(
|
||||||
if elapsed.get() < delay {
|
timeout_length as i32,
|
||||||
|
std::sync::atomic::Ordering::Relaxed,
|
||||||
|
) as i64
|
||||||
|
+ timeout_length;
|
||||||
|
|
||||||
|
if elapsed < delay {
|
||||||
if let Some(create_expiration_timeout) =
|
if let Some(create_expiration_timeout) =
|
||||||
&*create_expiration_timeout.borrow()
|
create_expiration_timeout.lock().unwrap().as_ref()
|
||||||
{
|
{
|
||||||
create_expiration_timeout();
|
create_expiration_timeout();
|
||||||
}
|
}
|
||||||
|
@ -705,12 +713,13 @@ fn handle_expiration<T>(delay: Option<i64>, set_cookie: WriteSignal<Option<T>>)
|
||||||
},
|
},
|
||||||
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();
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -735,7 +744,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;
|
||||||
|
|
||||||
|
@ -771,7 +780,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;
|
||||||
|
@ -859,7 +868,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(
|
||||||
|
@ -877,7 +886,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,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
|
||||||
|
@ -67,7 +68,8 @@ pub fn use_device_orientation() -> UseDeviceOrientationReturn {
|
||||||
.once(false),
|
.once(false),
|
||||||
);
|
);
|
||||||
|
|
||||||
on_cleanup(cleanup);
|
let cleanup = SendWrapper::new(cleanup);
|
||||||
|
on_cleanup(move || cleanup());
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
|
|
||||||
|
|
|
@ -90,12 +90,12 @@ 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()
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(web_sys::File::from)
|
.map(|f| SendWrapper::new(web_sys::File::from(f)))
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
set_files.update(move |f| *f = files);
|
set_files.update(move |f| *f = files);
|
||||||
|
@ -113,7 +113,11 @@ 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()
|
||||||
|
.map(SendWrapper::take)
|
||||||
|
.collect(),
|
||||||
event,
|
event,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -126,7 +130,11 @@ 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()
|
||||||
|
.map(SendWrapper::take)
|
||||||
|
.collect(),
|
||||||
event,
|
event,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -144,7 +152,11 @@ 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()
|
||||||
|
.map(SendWrapper::take)
|
||||||
|
.collect(),
|
||||||
event,
|
event,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -160,7 +172,11 @@ 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()
|
||||||
|
.map(SendWrapper::take)
|
||||||
|
.collect(),
|
||||||
event,
|
event,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -5,8 +5,8 @@ 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 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;
|
||||||
|
@ -154,8 +154,8 @@ where
|
||||||
let (event_source, set_event_source) = signal(None::<SendWrapper<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 (error, set_error) = signal(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 {
|
||||||
|
@ -174,7 +174,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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -188,7 +188,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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -222,14 +222,15 @@ where
|
||||||
// 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() {
|
||||||
|
@ -281,8 +282,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();
|
||||||
}
|
}
|
||||||
|
@ -326,7 +327,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.
|
||||||
|
|
|
@ -9,8 +9,9 @@ use gloo_timers::future::sleep;
|
||||||
use leptos::prelude::diagnostics::SpecialNonReactiveZone;
|
use leptos::prelude::diagnostics::SpecialNonReactiveZone;
|
||||||
use leptos::prelude::wrappers::read::Signal;
|
use leptos::prelude::wrappers::read::Signal;
|
||||||
use leptos::prelude::*;
|
use leptos::prelude::*;
|
||||||
|
use send_wrapper::SendWrapper;
|
||||||
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 +56,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 +71,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 {
|
||||||
|
@ -117,20 +118,22 @@ where
|
||||||
let el = el.into();
|
let el = el.into();
|
||||||
|
|
||||||
if el.is_instance_of::<web_sys::Window>() || el.is_instance_of::<web_sys::Document>() {
|
if el.is_instance_of::<web_sys::Window>() || el.is_instance_of::<web_sys::Document>() {
|
||||||
|
SendWrapper::new(
|
||||||
document()
|
document()
|
||||||
.document_element()
|
.document_element()
|
||||||
.expect("document element not found")
|
.expect("document element not found"),
|
||||||
|
)
|
||||||
} else {
|
} else {
|
||||||
el
|
SendWrapper::new(el)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
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 +218,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 +236,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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -173,11 +175,11 @@ where
|
||||||
.expect("failed to create IntersectionObserver");
|
.expect("failed to create IntersectionObserver");
|
||||||
|
|
||||||
for target in targets.iter().flatten() {
|
for target in targets.iter().flatten() {
|
||||||
let target: web_sys::Element = target.clone().into();
|
let target: web_sys::Element = target.clone().take().into();
|
||||||
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),
|
||||||
)
|
)
|
||||||
|
|
|
@ -6,6 +6,7 @@ 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::fmt::Display;
|
use std::fmt::Display;
|
||||||
use wasm_bindgen::{JsCast, JsValue};
|
use wasm_bindgen::{JsCast, JsValue};
|
||||||
|
|
||||||
|
@ -167,7 +168,7 @@ pub fn use_intl_number_format(options: UseIntlNumberFormatOptions) -> UseIntlNum
|
||||||
);
|
);
|
||||||
|
|
||||||
UseIntlNumberFormatReturn {
|
UseIntlNumberFormatReturn {
|
||||||
js_intl_number_format: number_format,
|
js_intl_number_format: SendWrapper::new(number_format),
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
@ -768,7 +769,7 @@ cfg_if! { if #[cfg(feature = "ssr")] {
|
||||||
/// Return type of [`use_intl_number_format`].
|
/// Return type of [`use_intl_number_format`].
|
||||||
pub struct UseIntlNumberFormatReturn {
|
pub struct UseIntlNumberFormatReturn {
|
||||||
/// The instance of [`Intl.NumberFormat`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/NumberFormat).
|
/// The instance of [`Intl.NumberFormat`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/NumberFormat).
|
||||||
pub js_intl_number_format: js_sys::Intl::NumberFormat,
|
pub js_intl_number_format: SendWrapper<js_sys::Intl::NumberFormat>,
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
|
|
||||||
|
@ -777,7 +778,7 @@ impl UseIntlNumberFormatReturn {
|
||||||
/// 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>
|
||||||
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();
|
||||||
|
@ -854,8 +855,8 @@ impl UseIntlNumberFormatReturn {
|
||||||
end: impl Into<MaybeSignal<NEnd>>,
|
end: impl Into<MaybeSignal<NEnd>>,
|
||||||
) -> Signal<String>
|
) -> Signal<String>
|
||||||
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>,
|
||||||
{
|
{
|
||||||
|
|
|
@ -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();
|
||||||
|
@ -135,7 +136,7 @@ where
|
||||||
.expect("failed to create MutationObserver");
|
.expect("failed to create MutationObserver");
|
||||||
|
|
||||||
for target in targets.iter().flatten() {
|
for target in targets.iter().flatten() {
|
||||||
let target: web_sys::Element = target.clone().into();
|
let target: web_sys::Element = target.clone().take().into();
|
||||||
let _ = obs.observe_with_options(&target, &options.clone().into());
|
let _ = obs.observe_with_options(&target, &options.clone().into());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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,7 +138,7 @@ where
|
||||||
.expect("failed to create ResizeObserver");
|
.expect("failed to create ResizeObserver");
|
||||||
|
|
||||||
for target in targets.iter().flatten() {
|
for target in targets.iter().flatten() {
|
||||||
let target: web_sys::Element = target.clone().into();
|
let target: web_sys::Element = target.clone().take().into();
|
||||||
obs.observe_with_options(&target, &options.clone().into());
|
obs.observe_with_options(&target, &options.clone().into());
|
||||||
}
|
}
|
||||||
observer.replace(Some(obs));
|
observer.replace(Some(obs));
|
||||||
|
@ -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 }
|
||||||
}
|
}
|
||||||
|
|
|
@ -221,6 +221,8 @@ where
|
||||||
let set_y = |_| {};
|
let set_y = |_| {};
|
||||||
let measure = || {};
|
let measure = || {};
|
||||||
} else {
|
} else {
|
||||||
|
use send_wrapper::SendWrapper;
|
||||||
|
|
||||||
let signal = element.into();
|
let signal = element.into();
|
||||||
let behavior = options.behavior;
|
let behavior = options.behavior;
|
||||||
|
|
||||||
|
@ -372,7 +374,7 @@ where
|
||||||
|
|
||||||
Signal::derive(move || {
|
Signal::derive(move || {
|
||||||
let element = signal.get();
|
let element = signal.get();
|
||||||
element.map(|element| element.into().unchecked_into::<web_sys::EventTarget>())
|
element.map(|element| SendWrapper::new(element.into().unchecked_into::<web_sys::EventTarget>()))
|
||||||
})
|
})
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -392,14 +394,14 @@ where
|
||||||
|
|
||||||
let _ = use_event_listener_with_options::<
|
let _ = use_event_listener_with_options::<
|
||||||
_,
|
_,
|
||||||
Signal<Option<web_sys::EventTarget>>,
|
Signal<Option<SendWrapper<web_sys::EventTarget>>>,
|
||||||
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<SendWrapper<web_sys::EventTarget>>>,
|
||||||
web_sys::EventTarget,
|
web_sys::EventTarget,
|
||||||
_,
|
_,
|
||||||
>(
|
>(
|
||||||
|
@ -412,7 +414,7 @@ where
|
||||||
|
|
||||||
let _ = use_event_listener_with_options::<
|
let _ = use_event_listener_with_options::<
|
||||||
_,
|
_,
|
||||||
Signal<Option<web_sys::EventTarget>>,
|
Signal<Option<SendWrapper<web_sys::EventTarget>>>,
|
||||||
web_sys::EventTarget,
|
web_sys::EventTarget,
|
||||||
_,
|
_,
|
||||||
>(
|
>(
|
||||||
|
|
|
@ -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)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -275,8 +275,10 @@ fn create_action_create_or_update_registration() -> Action<
|
||||||
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")))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
|
@ -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,
|
||||||
{
|
{
|
||||||
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,
|
||||||
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,
|
||||||
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;
|
||||||
|
|
|
@ -2,6 +2,7 @@ use crate::core::MaybeRwSignal;
|
||||||
use cfg_if::cfg_if;
|
use cfg_if::cfg_if;
|
||||||
use default_struct_builder::DefaultBuilder;
|
use default_struct_builder::DefaultBuilder;
|
||||||
use leptos::prelude::*;
|
use leptos::prelude::*;
|
||||||
|
use send_wrapper::SendWrapper;
|
||||||
use wasm_bindgen::{JsCast, JsValue};
|
use wasm_bindgen::{JsCast, JsValue};
|
||||||
|
|
||||||
/// Reactive [`mediaDevices.getUserMedia`](https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/getUserMedia) streaming.
|
/// Reactive [`mediaDevices.getUserMedia`](https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/getUserMedia) streaming.
|
||||||
|
@ -59,7 +60,8 @@ 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(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"))] {
|
||||||
|
@ -67,7 +69,10 @@ pub fn use_user_media_with_options(
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let stream = create_media(video, audio).await;
|
let stream = create_media(video, audio)
|
||||||
|
.await
|
||||||
|
.map(SendWrapper::new)
|
||||||
|
.map_err(SendWrapper::new);
|
||||||
|
|
||||||
set_stream.update(|s| *s = Some(stream));
|
set_stream.update(|s| *s = Some(stream));
|
||||||
} else {
|
} else {
|
||||||
|
@ -187,7 +192,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<SendWrapper<web_sys::MediaStream>, SendWrapper<JsValue>>>>,
|
||||||
|
|
||||||
/// 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,
|
||||||
|
|
|
@ -149,7 +149,7 @@ pub fn use_web_notification_with_options(
|
||||||
notification_value.set_onerror(Some(on_error_closure.unchecked_ref()));
|
notification_value.set_onerror(Some(on_error_closure.unchecked_ref()));
|
||||||
notification_value.set_onshow(Some(on_show_closure.unchecked_ref()));
|
notification_value.set_onshow(Some(on_show_closure.unchecked_ref()));
|
||||||
|
|
||||||
set_notification.set(Some(notification_value));
|
set_notification.set(Some(SendWrapper::new(notification_value)));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -237,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>,
|
||||||
|
@ -261,7 +261,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>,
|
||||||
|
@ -358,7 +358,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 +387,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 +409,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 +446,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 +473,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 +502,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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -524,7 +525,7 @@ where
|
||||||
onclose_closure.forget();
|
onclose_closure.forget();
|
||||||
}
|
}
|
||||||
|
|
||||||
ws_ref.set_value(Some(web_socket));
|
ws_ref.set_value(Some(SendWrapper::new(web_socket)));
|
||||||
}))
|
}))
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -642,7 +643,7 @@ 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.
|
||||||
|
@ -669,7 +670,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 +681,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 +711,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,
|
||||||
|
|
|
@ -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();
|
||||||
|
|
Loading…
Add table
Reference in a new issue