mirror of
https://github.com/adoyle0/leptos-use.git
synced 2025-01-23 00:59:22 -05:00
migrated away from CloneableFn... traits
This commit is contained in:
parent
19c4f00c5b
commit
58c54bb3e7
23 changed files with 210 additions and 415 deletions
|
@ -25,9 +25,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||
- The options `reconnect_limit` and `reconnect_interval` now take a `u64` instead of `Option<u64>` to improve DX.
|
||||
- The option `manual` has been renamed to `immediate` to make it more consistent with other functions.
|
||||
To port please note that `immediate` is the inverse of `manual` (`immediate` = `!manual`).
|
||||
- `use_color_mode`:
|
||||
- The optional `on_changed` handler parameters have changed slightly. Please refer to the docs for more details.
|
||||
- Throttled or debounced functions cannot be `FnOnce` anymore.
|
||||
- All traits `ClonableFn...` have been removed.
|
||||
|
||||
### Other Changes 🔥
|
||||
|
||||
- Callbacks in options don't require to be cloneable anymore
|
||||
- Callback in `use_raf_fn` doesn't require to be cloneable anymore
|
||||
|
||||
## [0.6.2] - 2023-08-03
|
||||
|
|
|
@ -16,7 +16,7 @@ homepage = "https://leptos-use.rs"
|
|||
leptos = "0.5.0-alpha"
|
||||
wasm-bindgen = "0.2"
|
||||
js-sys = "0.3"
|
||||
default-struct-builder = "0.4"
|
||||
default-struct-builder = "0.5"
|
||||
num = { version = "0.4", optional = true }
|
||||
serde = { version = "1", optional = true }
|
||||
serde_json = { version = "1", optional = true }
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
use crate::filter_builder_methods;
|
||||
use crate::storage::{StorageType, UseStorageError, UseStorageOptions};
|
||||
use crate::utils::{CloneableFnWithArg, DebounceOptions, FilterOptions, ThrottleOptions};
|
||||
use crate::utils::{DebounceOptions, FilterOptions, ThrottleOptions};
|
||||
use default_struct_builder::DefaultBuilder;
|
||||
use leptos::*;
|
||||
use std::rc::Rc;
|
||||
|
||||
macro_rules! use_specific_storage {
|
||||
($(#[$outer:meta])*
|
||||
|
@ -58,8 +59,7 @@ pub struct UseSpecificStorageOptions<T> {
|
|||
/// Defaults to simply returning the stored value.
|
||||
merge_defaults: fn(&str, &T) -> String,
|
||||
/// Optional callback whenever an error occurs. The callback takes an argument of type [`UseStorageError`].
|
||||
#[builder(into)]
|
||||
on_error: Box<dyn CloneableFnWithArg<UseStorageError>>,
|
||||
on_error: Rc<dyn Fn(UseStorageError)>,
|
||||
|
||||
/// Debounce or throttle the writing to storage whenever the value changes.
|
||||
filter: FilterOptions,
|
||||
|
@ -71,7 +71,7 @@ impl<T> Default for UseSpecificStorageOptions<T> {
|
|||
listen_to_storage_changes: true,
|
||||
write_defaults: true,
|
||||
merge_defaults: |stored_value, _default_value| stored_value.to_string(),
|
||||
on_error: Box::new(|_| ()),
|
||||
on_error: Rc::new(|_| ()),
|
||||
filter: Default::default(),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#![cfg_attr(feature = "ssr", allow(unused_variables, unused_imports, dead_code))]
|
||||
|
||||
use crate::core::MaybeRwSignal;
|
||||
use crate::utils::{CloneableFn, CloneableFnWithArg, FilterOptions};
|
||||
use crate::utils::FilterOptions;
|
||||
use crate::{
|
||||
filter_builder_methods, use_event_listener, watch_pausable_with_options, DebounceOptions,
|
||||
ThrottleOptions, WatchOptions, WatchPausableReturn,
|
||||
|
@ -12,6 +12,7 @@ use js_sys::Reflect;
|
|||
use leptos::*;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_json::Error;
|
||||
use std::rc::Rc;
|
||||
use std::time::Duration;
|
||||
use wasm_bindgen::{JsCast, JsValue};
|
||||
|
||||
|
@ -190,18 +191,18 @@ where
|
|||
let raw_init = data.get_untracked();
|
||||
|
||||
cfg_if! { if #[cfg(feature = "ssr")] {
|
||||
let remove: Box<dyn CloneableFn> = Box::new(|| {});
|
||||
let remove: Rc<dyn Fn()> = Rc::new(|| {});
|
||||
} else {
|
||||
let storage = storage_type.into_storage();
|
||||
|
||||
let remove: Box<dyn CloneableFn> = match storage {
|
||||
let remove: Rc<dyn Fn()> = match storage {
|
||||
Ok(Some(storage)) => {
|
||||
let write = {
|
||||
let on_error = on_error.clone();
|
||||
let storage = storage.clone();
|
||||
let key = key.to_string();
|
||||
|
||||
move |v: &T| {
|
||||
Rc::new(move |v: &T| {
|
||||
match serde_json::to_string(&v) {
|
||||
Ok(ref serialized) => match storage.get_item(&key) {
|
||||
Ok(old_value) => {
|
||||
|
@ -240,7 +241,7 @@ where
|
|||
on_error.clone()(UseStorageError::SerializationError(e));
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
};
|
||||
|
||||
let read = {
|
||||
|
@ -249,51 +250,53 @@ where
|
|||
let key = key.to_string();
|
||||
let raw_init = raw_init.clone();
|
||||
|
||||
move |event_detail: Option<StorageEventDetail>| -> Option<T> {
|
||||
let serialized_init = match serde_json::to_string(&raw_init) {
|
||||
Ok(serialized) => Some(serialized),
|
||||
Err(e) => {
|
||||
on_error.clone()(UseStorageError::DefaultSerializationError(e));
|
||||
None
|
||||
}
|
||||
};
|
||||
|
||||
let raw_value = if let Some(event_detail) = event_detail {
|
||||
event_detail.new_value
|
||||
} else {
|
||||
match storage.get_item(&key) {
|
||||
Ok(raw_value) => match raw_value {
|
||||
Some(raw_value) => Some(merge_defaults(&raw_value, &raw_init)),
|
||||
None => serialized_init.clone(),
|
||||
},
|
||||
Rc::new(
|
||||
move |event_detail: Option<StorageEventDetail>| -> Option<T> {
|
||||
let serialized_init = match serde_json::to_string(&raw_init) {
|
||||
Ok(serialized) => Some(serialized),
|
||||
Err(e) => {
|
||||
on_error.clone()(UseStorageError::StorageAccessError(e));
|
||||
on_error.clone()(UseStorageError::DefaultSerializationError(e));
|
||||
None
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
match raw_value {
|
||||
Some(raw_value) => match serde_json::from_str(&raw_value) {
|
||||
Ok(v) => Some(v),
|
||||
Err(e) => {
|
||||
on_error.clone()(UseStorageError::SerializationError(e));
|
||||
None
|
||||
}
|
||||
},
|
||||
None => {
|
||||
if let Some(serialized_init) = &serialized_init {
|
||||
if write_defaults {
|
||||
if let Err(e) = storage.set_item(&key, serialized_init) {
|
||||
on_error(UseStorageError::StorageAccessError(e));
|
||||
}
|
||||
let raw_value = if let Some(event_detail) = event_detail {
|
||||
event_detail.new_value
|
||||
} else {
|
||||
match storage.get_item(&key) {
|
||||
Ok(raw_value) => match raw_value {
|
||||
Some(raw_value) => Some(merge_defaults(&raw_value, &raw_init)),
|
||||
None => serialized_init.clone(),
|
||||
},
|
||||
Err(e) => {
|
||||
on_error.clone()(UseStorageError::StorageAccessError(e));
|
||||
None
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Some(raw_init)
|
||||
match raw_value {
|
||||
Some(raw_value) => match serde_json::from_str(&raw_value) {
|
||||
Ok(v) => Some(v),
|
||||
Err(e) => {
|
||||
on_error.clone()(UseStorageError::SerializationError(e));
|
||||
None
|
||||
}
|
||||
},
|
||||
None => {
|
||||
if let Some(serialized_init) = &serialized_init {
|
||||
if write_defaults {
|
||||
if let Err(e) = storage.set_item(&key, serialized_init) {
|
||||
on_error(UseStorageError::StorageAccessError(e));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Some(raw_init.clone())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
)
|
||||
};
|
||||
|
||||
let WatchPausableReturn {
|
||||
|
@ -311,15 +314,15 @@ where
|
|||
let storage = storage.clone();
|
||||
let raw_init = raw_init.clone();
|
||||
|
||||
move |event_detail: Option<StorageEventDetail>| {
|
||||
Rc::new(move |event_detail: Option<StorageEventDetail>| {
|
||||
if let Some(event_detail) = &event_detail {
|
||||
if event_detail.storage_area != Some(storage) {
|
||||
if event_detail.storage_area != Some(storage.clone()) {
|
||||
return;
|
||||
}
|
||||
|
||||
match &event_detail.key {
|
||||
None => {
|
||||
set_data.set(raw_init);
|
||||
set_data.set(raw_init.clone());
|
||||
return;
|
||||
}
|
||||
Some(event_key) => {
|
||||
|
@ -343,21 +346,25 @@ where
|
|||
} else {
|
||||
resume_watch();
|
||||
}
|
||||
}
|
||||
})
|
||||
};
|
||||
|
||||
let upd = update.clone();
|
||||
let update_from_custom_event =
|
||||
move |event: web_sys::CustomEvent| upd.clone()(Some(event.into()));
|
||||
let update_from_custom_event = {
|
||||
let update = Rc::clone(&update);
|
||||
|
||||
let upd = update.clone();
|
||||
let update_from_storage_event =
|
||||
move |event: web_sys::StorageEvent| upd.clone()(Some(event.into()));
|
||||
move |event: web_sys::CustomEvent| update(Some(event.into()))
|
||||
};
|
||||
|
||||
let update_from_storage_event = {
|
||||
let update = Rc::clone(&update);
|
||||
|
||||
move |event: web_sys::StorageEvent| update(Some(event.into()))
|
||||
};
|
||||
|
||||
if listen_to_storage_changes {
|
||||
let _ = use_event_listener(window(), ev::storage, update_from_storage_event);
|
||||
let _ = use_event_listener(
|
||||
window(),
|
||||
window(),
|
||||
ev::Custom::new(CUSTOM_STORAGE_EVENT_NAME),
|
||||
update_from_custom_event,
|
||||
);
|
||||
|
@ -367,22 +374,22 @@ where
|
|||
|
||||
let k = key.to_string();
|
||||
|
||||
Box::new(move || {
|
||||
Rc::new(move || {
|
||||
let _ = storage.remove_item(&k);
|
||||
})
|
||||
}
|
||||
Err(e) => {
|
||||
on_error(UseStorageError::NoStorage(e));
|
||||
Box::new(move || {})
|
||||
Rc::new(move || {})
|
||||
}
|
||||
_ => {
|
||||
// do nothing
|
||||
Box::new(move || {})
|
||||
Rc::new(move || {})
|
||||
}
|
||||
};
|
||||
}}
|
||||
|
||||
(data, set_data, move || remove.clone()())
|
||||
(data, set_data, move || remove())
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
|
@ -461,7 +468,7 @@ pub struct UseStorageOptions<T> {
|
|||
/// Defaults to simply returning the stored value.
|
||||
pub(crate) merge_defaults: fn(&str, &T) -> String,
|
||||
/// Optional callback whenever an error occurs. The callback takes an argument of type [`UseStorageError`].
|
||||
pub(crate) on_error: Box<dyn CloneableFnWithArg<UseStorageError>>,
|
||||
pub(crate) on_error: Rc<dyn Fn(UseStorageError)>,
|
||||
|
||||
/// Debounce or throttle the writing to storage whenever the value changes.
|
||||
pub(crate) filter: FilterOptions,
|
||||
|
@ -474,7 +481,7 @@ impl<T> Default for UseStorageOptions<T> {
|
|||
listen_to_storage_changes: true,
|
||||
write_defaults: true,
|
||||
merge_defaults: |stored_value, _default_value| stored_value.to_string(),
|
||||
on_error: Box::new(|_| ()),
|
||||
on_error: Rc::new(|_| ()),
|
||||
filter: Default::default(),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,11 +7,11 @@ use std::fmt::{Display, Formatter};
|
|||
|
||||
use crate::core::StorageType;
|
||||
use crate::use_preferred_dark;
|
||||
use crate::utils::CloneableFnWithArg;
|
||||
use cfg_if::cfg_if;
|
||||
use default_struct_builder::DefaultBuilder;
|
||||
use leptos::*;
|
||||
use std::marker::PhantomData;
|
||||
use std::rc::Rc;
|
||||
use wasm_bindgen::JsCast;
|
||||
|
||||
/// Reactive color mode (dark / light / customs) with auto data persistence.
|
||||
|
@ -217,10 +217,7 @@ where
|
|||
};
|
||||
|
||||
let on_changed = move |mode: ColorMode| {
|
||||
on_changed(UseColorModeOnChangeArgs {
|
||||
mode,
|
||||
default_handler: Box::new(default_on_changed.clone()),
|
||||
});
|
||||
on_changed(mode, Rc::new(default_on_changed.clone()));
|
||||
};
|
||||
|
||||
create_effect({
|
||||
|
@ -333,16 +330,6 @@ impl From<String> for ColorMode {
|
|||
}
|
||||
}
|
||||
|
||||
/// Arguments to [`UseColorModeOptions::on_changed`]
|
||||
#[derive(Clone)]
|
||||
pub struct UseColorModeOnChangeArgs {
|
||||
/// The color mode to change to.
|
||||
pub mode: ColorMode,
|
||||
|
||||
/// The default handler that would have been called if the `on_changed` handler had not been specified.
|
||||
pub default_handler: Box<dyn CloneableFnWithArg<ColorMode>>,
|
||||
}
|
||||
|
||||
#[derive(DefaultBuilder)]
|
||||
pub struct UseColorModeOptions<El, T>
|
||||
where
|
||||
|
@ -367,7 +354,10 @@ where
|
|||
/// Custom handler that is called on updates.
|
||||
/// If specified this will override the default behavior.
|
||||
/// To get the default behaviour back you can call the provided `default_handler` function.
|
||||
on_changed: Box<dyn CloneableFnWithArg<UseColorModeOnChangeArgs>>,
|
||||
/// It takes two parameters:
|
||||
/// - `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.
|
||||
on_changed: OnChangedFn,
|
||||
|
||||
/// When provided, `useStorage` will be skipped.
|
||||
/// Storage requires the *create feature* **`storage`** to be enabled.
|
||||
|
@ -411,6 +401,8 @@ where
|
|||
_marker: PhantomData<T>,
|
||||
}
|
||||
|
||||
type OnChangedFn = Rc<dyn Fn(ColorMode, Rc<dyn Fn(ColorMode)>)>;
|
||||
|
||||
impl Default for UseColorModeOptions<&'static str, web_sys::Element> {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
|
@ -418,9 +410,7 @@ impl Default for UseColorModeOptions<&'static str, web_sys::Element> {
|
|||
attribute: "class".into(),
|
||||
initial_value: ColorMode::Auto.into(),
|
||||
custom_modes: vec![],
|
||||
on_changed: Box::new(move |args: UseColorModeOnChangeArgs| {
|
||||
(args.default_handler)(args.mode)
|
||||
}),
|
||||
on_changed: Rc::new(move |mode, default_handler| (default_handler)(mode)),
|
||||
storage_signal: None,
|
||||
storage_key: "leptos-use-color-scheme".into(),
|
||||
storage: StorageType::default(),
|
||||
|
|
|
@ -77,7 +77,7 @@ pub fn use_debounce_fn<F, R>(
|
|||
ms: impl Into<MaybeSignal<f64>> + 'static,
|
||||
) -> impl Fn() -> Rc<RefCell<Option<R>>> + Clone
|
||||
where
|
||||
F: FnOnce() -> R + Clone + 'static,
|
||||
F: Fn() -> R + Clone + 'static,
|
||||
R: 'static,
|
||||
{
|
||||
use_debounce_fn_with_options(func, ms, DebounceOptions::default())
|
||||
|
@ -90,10 +90,10 @@ pub fn use_debounce_fn_with_options<F, R>(
|
|||
options: DebounceOptions,
|
||||
) -> impl Fn() -> Rc<RefCell<Option<R>>> + Clone
|
||||
where
|
||||
F: FnOnce() -> R + Clone + 'static,
|
||||
F: Fn() -> R + Clone + 'static,
|
||||
R: 'static,
|
||||
{
|
||||
create_filter_wrapper(Box::new(debounce_filter(ms, options)), func)
|
||||
create_filter_wrapper(Rc::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.
|
||||
|
@ -102,7 +102,7 @@ pub fn use_debounce_fn_with_arg<F, Arg, R>(
|
|||
ms: impl Into<MaybeSignal<f64>> + 'static,
|
||||
) -> impl Fn(Arg) -> Rc<RefCell<Option<R>>> + Clone
|
||||
where
|
||||
F: FnOnce(Arg) -> R + Clone + 'static,
|
||||
F: Fn(Arg) -> R + Clone + 'static,
|
||||
Arg: Clone + 'static,
|
||||
R: 'static,
|
||||
{
|
||||
|
@ -116,9 +116,9 @@ pub fn use_debounce_fn_with_arg_and_options<F, Arg, R>(
|
|||
options: DebounceOptions,
|
||||
) -> impl Fn(Arg) -> Rc<RefCell<Option<R>>> + Clone
|
||||
where
|
||||
F: FnOnce(Arg) -> R + Clone + 'static,
|
||||
F: Fn(Arg) -> R + Clone + 'static,
|
||||
Arg: Clone + 'static,
|
||||
R: 'static,
|
||||
{
|
||||
create_filter_wrapper_with_arg(Box::new(debounce_filter(ms, options)), func)
|
||||
create_filter_wrapper_with_arg(Rc::new(debounce_filter(ms, options)), func)
|
||||
}
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
use crate::core::{ElementMaybeSignal, MaybeRwSignal, PointerType, Position};
|
||||
use crate::use_event_listener_with_options;
|
||||
use crate::utils::{CloneableFnMutWithArg, CloneableFnWithArgAndReturn};
|
||||
use default_struct_builder::DefaultBuilder;
|
||||
use leptos::ev::{pointerdown, pointermove, pointerup};
|
||||
use leptos::*;
|
||||
use std::marker::PhantomData;
|
||||
use std::rc::Rc;
|
||||
use wasm_bindgen::JsCast;
|
||||
use web_sys::PointerEvent;
|
||||
|
||||
|
@ -134,7 +134,7 @@ where
|
|||
x: event.client_x() as f64 - rect.left(),
|
||||
y: event.client_y() as f64 - rect.top(),
|
||||
};
|
||||
if !on_start.clone()(UseDraggableCallbackArgs {
|
||||
if !on_start(UseDraggableCallbackArgs {
|
||||
position,
|
||||
event: event.clone(),
|
||||
}) {
|
||||
|
@ -159,7 +159,7 @@ where
|
|||
y: event.client_y() as f64 - start_position.y,
|
||||
};
|
||||
set_position.set(position);
|
||||
on_move.clone()(UseDraggableCallbackArgs {
|
||||
on_move(UseDraggableCallbackArgs {
|
||||
position,
|
||||
event: event.clone(),
|
||||
});
|
||||
|
@ -176,7 +176,7 @@ where
|
|||
return;
|
||||
}
|
||||
set_start_position.set(None);
|
||||
on_end.clone()(UseDraggableCallbackArgs {
|
||||
on_end(UseDraggableCallbackArgs {
|
||||
position: position.get_untracked(),
|
||||
event: event.clone(),
|
||||
});
|
||||
|
@ -253,13 +253,13 @@ where
|
|||
initial_value: MaybeRwSignal<Position>,
|
||||
|
||||
/// Callback when the dragging starts. Return `false` to prevent dragging.
|
||||
on_start: Box<dyn CloneableFnWithArgAndReturn<UseDraggableCallbackArgs, bool>>,
|
||||
on_start: Rc<dyn Fn(UseDraggableCallbackArgs) -> bool>,
|
||||
|
||||
/// Callback during dragging.
|
||||
on_move: Box<dyn CloneableFnMutWithArg<UseDraggableCallbackArgs>>,
|
||||
on_move: Rc<dyn Fn(UseDraggableCallbackArgs)>,
|
||||
|
||||
/// Callback when dragging end.
|
||||
on_end: Box<dyn CloneableFnMutWithArg<UseDraggableCallbackArgs>>,
|
||||
on_end: Rc<dyn Fn(UseDraggableCallbackArgs)>,
|
||||
|
||||
#[builder(skip)]
|
||||
_marker1: PhantomData<DragT>,
|
||||
|
@ -284,9 +284,9 @@ impl Default
|
|||
handle: None,
|
||||
pointer_types: vec![PointerType::Mouse, PointerType::Touch, PointerType::Pen],
|
||||
initial_value: MaybeRwSignal::default(),
|
||||
on_start: Box::new(|_| true),
|
||||
on_move: Box::new(|_| {}),
|
||||
on_end: Box::new(|_| {}),
|
||||
on_start: Rc::new(|_| true),
|
||||
on_move: Rc::new(|_| {}),
|
||||
on_end: Rc::new(|_| {}),
|
||||
_marker1: PhantomData,
|
||||
_marker2: PhantomData,
|
||||
}
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
use crate::core::ElementMaybeSignal;
|
||||
use crate::use_event_listener;
|
||||
use crate::utils::CloneableFnMutWithArg;
|
||||
use default_struct_builder::DefaultBuilder;
|
||||
use leptos::ev::{dragenter, dragleave, dragover, drop};
|
||||
use leptos::*;
|
||||
use std::fmt::{Debug, Formatter};
|
||||
use std::rc::Rc;
|
||||
|
||||
/// Create a zone where files can be dropped.
|
||||
///
|
||||
|
@ -65,10 +66,10 @@ where
|
|||
T: Into<web_sys::EventTarget> + Clone + 'static,
|
||||
{
|
||||
let UseDropZoneOptions {
|
||||
mut on_drop,
|
||||
mut on_enter,
|
||||
mut on_leave,
|
||||
mut on_over,
|
||||
on_drop,
|
||||
on_enter,
|
||||
on_leave,
|
||||
on_over,
|
||||
} = options;
|
||||
|
||||
let (is_over_drop_zone, set_over_drop_zone) = create_signal(false);
|
||||
|
@ -147,16 +148,33 @@ where
|
|||
}
|
||||
|
||||
/// Options for [`use_drop_zone_with_options`].
|
||||
#[derive(DefaultBuilder, Default, Clone, Debug)]
|
||||
#[derive(DefaultBuilder, Clone)]
|
||||
pub struct UseDropZoneOptions {
|
||||
/// Event handler for the [`drop`](https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/drop_event) event
|
||||
on_drop: Box<dyn CloneableFnMutWithArg<UseDropZoneEvent>>,
|
||||
on_drop: Rc<dyn Fn(UseDropZoneEvent)>,
|
||||
/// Event handler for the [`dragenter`](https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/dragenter_event) event
|
||||
on_enter: Box<dyn CloneableFnMutWithArg<UseDropZoneEvent>>,
|
||||
on_enter: Rc<dyn Fn(UseDropZoneEvent)>,
|
||||
/// Event handler for the [`dragleave`](https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/dragleave_event) event
|
||||
on_leave: Box<dyn CloneableFnMutWithArg<UseDropZoneEvent>>,
|
||||
on_leave: Rc<dyn Fn(UseDropZoneEvent)>,
|
||||
/// Event handler for the [`dragover`](https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/dragover_event) event
|
||||
on_over: Box<dyn CloneableFnMutWithArg<UseDropZoneEvent>>,
|
||||
on_over: Rc<dyn Fn(UseDropZoneEvent)>,
|
||||
}
|
||||
|
||||
impl Default for UseDropZoneOptions {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
on_drop: Rc::new(|_| {}),
|
||||
on_enter: Rc::new(|_| {}),
|
||||
on_leave: Rc::new(|_| {}),
|
||||
on_over: Rc::new(|_| {}),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Debug for UseDropZoneOptions {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "UseDropZoneOptions")
|
||||
}
|
||||
}
|
||||
|
||||
/// Event passed as argument to the event handler functions of `UseDropZoneOptions`.
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
use crate::utils::{CloneableFnWithArg, Pausable};
|
||||
use crate::utils::Pausable;
|
||||
use crate::{use_interval_fn_with_options, UseIntervalFnOptions};
|
||||
use default_struct_builder::DefaultBuilder;
|
||||
use std::rc::Rc;
|
||||
|
||||
use leptos::*;
|
||||
|
||||
|
@ -61,7 +62,7 @@ where
|
|||
|
||||
let cb = move || {
|
||||
update();
|
||||
callback.clone()(counter.get());
|
||||
callback(counter.get());
|
||||
};
|
||||
|
||||
let Pausable {
|
||||
|
@ -93,14 +94,14 @@ pub struct UseIntervalOptions {
|
|||
immediate: bool,
|
||||
|
||||
/// Callback on every interval.
|
||||
callback: Box<dyn CloneableFnWithArg<u64>>,
|
||||
callback: Rc<dyn Fn(u64)>,
|
||||
}
|
||||
|
||||
impl Default for UseIntervalOptions {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
immediate: true,
|
||||
callback: Box::new(|_: u64| {}),
|
||||
callback: Rc::new(|_: u64| {}),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
#![cfg_attr(feature = "ssr", allow(unused_variables, unused_imports, dead_code))]
|
||||
|
||||
use crate::use_event_listener;
|
||||
use crate::utils::CloneableFnMutWithArg;
|
||||
use cfg_if::cfg_if;
|
||||
use leptos::ev::change;
|
||||
use leptos::*;
|
||||
|
@ -48,8 +47,7 @@ pub fn use_media_query(query: impl Into<MaybeSignal<String>>) -> Signal<bool> {
|
|||
let media_query: Rc<RefCell<Option<web_sys::MediaQueryList>>> = Rc::new(RefCell::new(None));
|
||||
let remove_listener: RemoveListener = Rc::new(RefCell::new(None));
|
||||
|
||||
let listener: Rc<RefCell<Box<dyn CloneableFnMutWithArg<web_sys::Event>>>> =
|
||||
Rc::new(RefCell::new(Box::new(|_| {})));
|
||||
let listener = Rc::new(RefCell::new(Rc::new(|_| {}) as Rc<dyn Fn(web_sys::Event)>));
|
||||
|
||||
let cleanup = {
|
||||
let remove_listener = Rc::clone(&remove_listener);
|
||||
|
@ -65,7 +63,7 @@ pub fn use_media_query(query: impl Into<MaybeSignal<String>>) -> Signal<bool> {
|
|||
let cleanup = cleanup.clone();
|
||||
let listener = Rc::clone(&listener);
|
||||
|
||||
move || {
|
||||
Rc::new(move || {
|
||||
cleanup();
|
||||
|
||||
let mut media_query = media_query.borrow_mut();
|
||||
|
@ -74,21 +72,22 @@ pub fn use_media_query(query: impl Into<MaybeSignal<String>>) -> Signal<bool> {
|
|||
if let Some(media_query) = media_query.as_ref() {
|
||||
set_matches.set(media_query.matches());
|
||||
|
||||
let listener = Rc::clone(&*listener.borrow());
|
||||
|
||||
remove_listener.replace(Some(Box::new(use_event_listener(
|
||||
media_query.clone(),
|
||||
media_query.clone(),
|
||||
change,
|
||||
listener.borrow().clone(),
|
||||
move |e| listener(e),
|
||||
))));
|
||||
} else {
|
||||
set_matches.set(false);
|
||||
}
|
||||
}
|
||||
})
|
||||
};
|
||||
|
||||
{
|
||||
let update = update.clone();
|
||||
listener
|
||||
.replace(Box::new(move |_| update()) as Box<dyn CloneableFnMutWithArg<web_sys::Event>>);
|
||||
let update = Rc::clone(&update);
|
||||
listener.replace(Rc::new(move |_| update()) as Rc<dyn Fn(web_sys::Event)>);
|
||||
}
|
||||
|
||||
create_effect(move |_| update());
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
use crate::core::ElementMaybeSignal;
|
||||
use crate::use_event_listener::use_event_listener_with_options;
|
||||
use crate::utils::CloneableFnWithArg;
|
||||
use crate::{use_debounce_fn_with_arg, use_throttle_fn_with_arg_and_options, ThrottleOptions};
|
||||
use default_struct_builder::DefaultBuilder;
|
||||
use leptos::ev::EventDescriptor;
|
||||
use leptos::*;
|
||||
use std::borrow::Cow;
|
||||
use std::rc::Rc;
|
||||
use wasm_bindgen::JsCast;
|
||||
|
||||
/// Reactive scroll position and state.
|
||||
|
@ -232,7 +232,7 @@ where
|
|||
});
|
||||
|
||||
let on_scroll_end = {
|
||||
let on_stop = options.on_stop.clone();
|
||||
let on_stop = Rc::clone(&options.on_stop);
|
||||
|
||||
move |e| {
|
||||
if !is_scrolling.get_untracked() {
|
||||
|
@ -328,7 +328,7 @@ where
|
|||
};
|
||||
|
||||
let on_scroll_handler = {
|
||||
let on_scroll = options.on_scroll.clone();
|
||||
let on_scroll = Rc::clone(&options.on_scroll);
|
||||
|
||||
move |e: web_sys::Event| {
|
||||
let target: web_sys::Element = event_target(&e);
|
||||
|
@ -441,10 +441,10 @@ pub struct UseScrollOptions {
|
|||
offset: ScrollOffset,
|
||||
|
||||
/// Callback when scrolling is happening.
|
||||
on_scroll: Box<dyn CloneableFnWithArg<web_sys::Event>>,
|
||||
on_scroll: Rc<dyn Fn(web_sys::Event)>,
|
||||
|
||||
/// Callback when scrolling stops (after `idle` + `throttle` milliseconds have passed).
|
||||
on_stop: Box<dyn CloneableFnWithArg<web_sys::Event>>,
|
||||
on_stop: Rc<dyn Fn(web_sys::Event)>,
|
||||
|
||||
/// Options passed to the `addEventListener("scroll", ...)` call
|
||||
event_listener_options: web_sys::AddEventListenerOptions,
|
||||
|
@ -461,8 +461,8 @@ impl Default for UseScrollOptions {
|
|||
throttle: 0.0,
|
||||
idle: 200.0,
|
||||
offset: ScrollOffset::default(),
|
||||
on_scroll: Box::new(|_| {}),
|
||||
on_stop: Box::new(|_| {}),
|
||||
on_scroll: Rc::new(|_| {}),
|
||||
on_stop: Rc::new(|_| {}),
|
||||
event_listener_options: Default::default(),
|
||||
behavior: Default::default(),
|
||||
}
|
||||
|
|
|
@ -73,7 +73,7 @@ pub fn use_throttle_fn<F, R>(
|
|||
ms: impl Into<MaybeSignal<f64>> + 'static,
|
||||
) -> impl Fn() -> Rc<RefCell<Option<R>>> + Clone
|
||||
where
|
||||
F: FnOnce() -> R + Clone + 'static,
|
||||
F: Fn() -> R + Clone + 'static,
|
||||
R: 'static,
|
||||
{
|
||||
use_throttle_fn_with_options(func, ms, Default::default())
|
||||
|
@ -86,10 +86,10 @@ pub fn use_throttle_fn_with_options<F, R>(
|
|||
options: ThrottleOptions,
|
||||
) -> impl Fn() -> Rc<RefCell<Option<R>>> + Clone
|
||||
where
|
||||
F: FnOnce() -> R + Clone + 'static,
|
||||
F: Fn() -> R + Clone + 'static,
|
||||
R: 'static,
|
||||
{
|
||||
create_filter_wrapper(Box::new(throttle_filter(ms, options)), func)
|
||||
create_filter_wrapper(Rc::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.
|
||||
|
@ -98,7 +98,7 @@ pub fn use_throttle_fn_with_arg<F, Arg, R>(
|
|||
ms: impl Into<MaybeSignal<f64>> + 'static,
|
||||
) -> impl Fn(Arg) -> Rc<RefCell<Option<R>>> + Clone
|
||||
where
|
||||
F: FnOnce(Arg) -> R + Clone + 'static,
|
||||
F: Fn(Arg) -> R + Clone + 'static,
|
||||
Arg: Clone + 'static,
|
||||
R: 'static,
|
||||
{
|
||||
|
@ -112,9 +112,9 @@ pub fn use_throttle_fn_with_arg_and_options<F, Arg, R>(
|
|||
options: ThrottleOptions,
|
||||
) -> impl Fn(Arg) -> Rc<RefCell<Option<R>>> + Clone
|
||||
where
|
||||
F: FnOnce(Arg) -> R + Clone + 'static,
|
||||
F: Fn(Arg) -> R + Clone + 'static,
|
||||
Arg: Clone + 'static,
|
||||
R: 'static,
|
||||
{
|
||||
create_filter_wrapper_with_arg(Box::new(throttle_filter(ms, options)), func)
|
||||
create_filter_wrapper_with_arg(Rc::new(throttle_filter(ms, options)), func)
|
||||
}
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
#![cfg_attr(feature = "ssr", allow(unused_variables, unused_imports, dead_code))]
|
||||
|
||||
use cfg_if::cfg_if;
|
||||
use core::fmt;
|
||||
use leptos::{leptos_dom::helpers::TimeoutHandle, *};
|
||||
use std::rc::Rc;
|
||||
use std::time::Duration;
|
||||
|
@ -12,8 +11,6 @@ use js_sys::Array;
|
|||
use wasm_bindgen::{prelude::*, JsCast, JsValue};
|
||||
use web_sys::{BinaryType, CloseEvent, Event, MessageEvent, WebSocket};
|
||||
|
||||
use crate::utils::CloneableFnWithArg;
|
||||
|
||||
/// Creating and managing a [Websocket](https://developer.mozilla.org/en-US/docs/Web/API/WebSocket) connection.
|
||||
///
|
||||
/// ## Demo
|
||||
|
@ -102,15 +99,24 @@ pub fn use_websocket_with_options(
|
|||
> {
|
||||
let url = url.to_string();
|
||||
|
||||
let UseWebSocketOptions {
|
||||
on_open,
|
||||
on_message,
|
||||
on_message_bytes,
|
||||
on_error,
|
||||
on_close,
|
||||
reconnect_limit,
|
||||
reconnect_interval,
|
||||
immediate,
|
||||
protocols,
|
||||
} = options;
|
||||
|
||||
let (ready_state, set_ready_state) = create_signal(ConnectionReadyState::Closed);
|
||||
let (message, set_message) = create_signal(None);
|
||||
let (message_bytes, set_message_bytes) = create_signal(None);
|
||||
let ws_ref: StoredValue<Option<WebSocket>> = store_value(None);
|
||||
|
||||
let reconnect_limit = options.reconnect_limit;
|
||||
|
||||
let reconnect_timer_ref: StoredValue<Option<TimeoutHandle>> = store_value(None);
|
||||
let immediate = options.immediate;
|
||||
|
||||
let reconnect_times_ref: StoredValue<u64> = store_value(0);
|
||||
let unmounted_ref = store_value(false);
|
||||
|
@ -118,14 +124,6 @@ pub fn use_websocket_with_options(
|
|||
let connect_ref: StoredValue<Option<Rc<dyn Fn()>>> = store_value(None);
|
||||
|
||||
cfg_if! { if #[cfg(not(feature = "ssr"))] {
|
||||
let on_open_ref = store_value(options.on_open);
|
||||
let on_message_ref = store_value(options.on_message);
|
||||
let on_message_bytes_ref = store_value(options.on_message_bytes);
|
||||
let on_error_ref = store_value(options.on_error);
|
||||
let on_close_ref = store_value(options.on_close);
|
||||
|
||||
let reconnect_interval = options.reconnect_interval;
|
||||
let protocols = options.protocols;
|
||||
|
||||
let reconnect_ref: StoredValue<Option<Rc<dyn Fn()>>> = store_value(None);
|
||||
reconnect_ref.set_value({
|
||||
|
@ -181,13 +179,14 @@ pub fn use_websocket_with_options(
|
|||
|
||||
// onopen handler
|
||||
{
|
||||
let on_open = Rc::clone(&on_open);
|
||||
|
||||
let onopen_closure = Closure::wrap(Box::new(move |e: Event| {
|
||||
if unmounted_ref.get_value() {
|
||||
return;
|
||||
}
|
||||
|
||||
let callback = on_open_ref.get_value();
|
||||
callback(e);
|
||||
on_open(e);
|
||||
|
||||
set_ready_state.set(ConnectionReadyState::Open);
|
||||
}) as Box<dyn FnMut(Event)>);
|
||||
|
@ -198,6 +197,9 @@ pub fn use_websocket_with_options(
|
|||
|
||||
// onmessage handler
|
||||
{
|
||||
let on_message = Rc::clone(&on_message);
|
||||
let on_message_bytes = Rc::clone(&on_message_bytes);
|
||||
|
||||
let onmessage_closure = Closure::wrap(Box::new(move |e: MessageEvent| {
|
||||
if unmounted_ref.get_value() {
|
||||
return;
|
||||
|
@ -211,8 +213,7 @@ pub fn use_websocket_with_options(
|
|||
},
|
||||
|txt| {
|
||||
let txt = String::from(&txt);
|
||||
let callback = on_message_ref.get_value();
|
||||
callback(txt.clone());
|
||||
on_message(txt.clone());
|
||||
|
||||
set_message.set(Some(txt));
|
||||
},
|
||||
|
@ -221,8 +222,7 @@ pub fn use_websocket_with_options(
|
|||
|array_buffer| {
|
||||
let array = js_sys::Uint8Array::new(&array_buffer);
|
||||
let array = array.to_vec();
|
||||
let callback = on_message_bytes_ref.get_value();
|
||||
callback(array.clone());
|
||||
on_message_bytes(array.clone());
|
||||
|
||||
set_message_bytes.set(Some(array));
|
||||
},
|
||||
|
@ -235,6 +235,8 @@ pub fn use_websocket_with_options(
|
|||
|
||||
// onerror handler
|
||||
{
|
||||
let on_error = Rc::clone(&on_error);
|
||||
|
||||
let onerror_closure = Closure::wrap(Box::new(move |e: Event| {
|
||||
if unmounted_ref.get_value() {
|
||||
return;
|
||||
|
@ -244,8 +246,7 @@ pub fn use_websocket_with_options(
|
|||
reconnect();
|
||||
}
|
||||
|
||||
let callback = on_error_ref.get_value();
|
||||
callback(e);
|
||||
on_error(e);
|
||||
|
||||
set_ready_state.set(ConnectionReadyState::Closed);
|
||||
}) as Box<dyn FnMut(Event)>);
|
||||
|
@ -255,6 +256,8 @@ pub fn use_websocket_with_options(
|
|||
|
||||
// onclose handler
|
||||
{
|
||||
let on_close = Rc::clone(&on_close);
|
||||
|
||||
let onclose_closure = Closure::wrap(Box::new(move |e: CloseEvent| {
|
||||
if unmounted_ref.get_value() {
|
||||
return;
|
||||
|
@ -264,8 +267,7 @@ pub fn use_websocket_with_options(
|
|||
reconnect();
|
||||
}
|
||||
|
||||
let callback = on_close_ref.get_value();
|
||||
callback(e);
|
||||
on_close(e);
|
||||
|
||||
set_ready_state.set(ConnectionReadyState::Closed);
|
||||
})
|
||||
|
@ -348,15 +350,15 @@ pub fn use_websocket_with_options(
|
|||
#[derive(DefaultBuilder)]
|
||||
pub struct UseWebSocketOptions {
|
||||
/// `WebSocket` connect callback.
|
||||
on_open: Box<dyn CloneableFnWithArg<Event>>,
|
||||
on_open: Rc<dyn Fn(Event)>,
|
||||
/// `WebSocket` message callback for text.
|
||||
on_message: Box<dyn CloneableFnWithArg<String>>,
|
||||
on_message: Rc<dyn Fn(String)>,
|
||||
/// `WebSocket` message callback for binary.
|
||||
on_message_bytes: Box<dyn CloneableFnWithArg<Vec<u8>>>,
|
||||
on_message_bytes: Rc<dyn Fn(Vec<u8>)>,
|
||||
/// `WebSocket` error callback.
|
||||
on_error: Box<dyn CloneableFnWithArg<Event>>,
|
||||
on_error: Rc<dyn Fn(Event)>,
|
||||
/// `WebSocket` close callback.
|
||||
on_close: Box<dyn CloneableFnWithArg<CloseEvent>>,
|
||||
on_close: Rc<dyn Fn(CloseEvent)>,
|
||||
/// Retry times. Defaults to 3.
|
||||
reconnect_limit: u64,
|
||||
/// Retry interval in ms. Defaults to 3000.
|
||||
|
@ -372,11 +374,11 @@ pub struct UseWebSocketOptions {
|
|||
impl Default for UseWebSocketOptions {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
on_open: Box::new(|_| {}),
|
||||
on_message: Box::new(|_| {}),
|
||||
on_message_bytes: Box::new(|_| {}),
|
||||
on_error: Box::new(|_| {}),
|
||||
on_close: Box::new(|_| {}),
|
||||
on_open: Rc::new(|_| {}),
|
||||
on_message: Rc::new(|_| {}),
|
||||
on_message_bytes: Rc::new(|_| {}),
|
||||
on_error: Rc::new(|_| {}),
|
||||
on_close: Rc::new(|_| {}),
|
||||
reconnect_limit: 3,
|
||||
reconnect_interval: 3000,
|
||||
immediate: true,
|
||||
|
|
|
@ -1,43 +0,0 @@
|
|||
mod mut_;
|
||||
mod mut_with_arg;
|
||||
mod with_arg;
|
||||
mod with_arg_and_return;
|
||||
mod with_return;
|
||||
|
||||
pub use mut_::*;
|
||||
pub use mut_with_arg::*;
|
||||
use std::fmt::Debug;
|
||||
pub use with_arg::*;
|
||||
pub use with_arg_and_return::*;
|
||||
pub use with_return::*;
|
||||
|
||||
pub trait CloneableFn: FnOnce() {
|
||||
fn clone_box(&self) -> Box<dyn CloneableFn>;
|
||||
}
|
||||
|
||||
impl<F> CloneableFn for F
|
||||
where
|
||||
F: FnOnce() + Clone + 'static,
|
||||
{
|
||||
fn clone_box(&self) -> Box<dyn CloneableFn> {
|
||||
Box::new(self.clone())
|
||||
}
|
||||
}
|
||||
|
||||
impl Clone for Box<dyn CloneableFn> {
|
||||
fn clone(&self) -> Self {
|
||||
(**self).clone_box()
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for Box<dyn CloneableFn> {
|
||||
fn default() -> Self {
|
||||
Box::new(|| {})
|
||||
}
|
||||
}
|
||||
|
||||
impl Debug for Box<dyn CloneableFn> {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "Box<dyn CloneableFn>",)
|
||||
}
|
||||
}
|
|
@ -1,32 +0,0 @@
|
|||
use std::fmt::Debug;
|
||||
|
||||
pub trait CloneableFnMut: FnMut() {
|
||||
fn clone_box(&self) -> Box<dyn CloneableFnMut>;
|
||||
}
|
||||
|
||||
impl<F> CloneableFnMut for F
|
||||
where
|
||||
F: FnMut() + Clone + 'static,
|
||||
{
|
||||
fn clone_box(&self) -> Box<dyn CloneableFnMut> {
|
||||
Box::new(self.clone())
|
||||
}
|
||||
}
|
||||
|
||||
impl Clone for Box<dyn CloneableFnMut> {
|
||||
fn clone(&self) -> Self {
|
||||
(**self).clone_box()
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for Box<dyn CloneableFnMut> {
|
||||
fn default() -> Self {
|
||||
Box::new(|| {})
|
||||
}
|
||||
}
|
||||
|
||||
impl Debug for Box<dyn CloneableFnMut> {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "Box<dyn CloneableFnMut>",)
|
||||
}
|
||||
}
|
|
@ -1,36 +0,0 @@
|
|||
use std::fmt::Debug;
|
||||
|
||||
pub trait CloneableFnMutWithArg<Arg>: FnMut(Arg) {
|
||||
fn clone_box(&self) -> Box<dyn CloneableFnMutWithArg<Arg>>;
|
||||
}
|
||||
|
||||
impl<F, Arg> CloneableFnMutWithArg<Arg> for F
|
||||
where
|
||||
F: FnMut(Arg) + Clone + 'static,
|
||||
{
|
||||
fn clone_box(&self) -> Box<dyn CloneableFnMutWithArg<Arg>> {
|
||||
Box::new(self.clone())
|
||||
}
|
||||
}
|
||||
|
||||
impl<Arg> Clone for Box<dyn CloneableFnMutWithArg<Arg>> {
|
||||
fn clone(&self) -> Self {
|
||||
(**self).clone_box()
|
||||
}
|
||||
}
|
||||
|
||||
impl<Arg> Default for Box<dyn CloneableFnMutWithArg<Arg>> {
|
||||
fn default() -> Self {
|
||||
Box::new(|_| {})
|
||||
}
|
||||
}
|
||||
|
||||
impl<Arg> Debug for Box<dyn CloneableFnMutWithArg<Arg>> {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
"Box<dyn CloneableFnMutWithArg<{}>>",
|
||||
std::any::type_name::<Arg>()
|
||||
)
|
||||
}
|
||||
}
|
|
@ -1,36 +0,0 @@
|
|||
use std::fmt::Debug;
|
||||
|
||||
pub trait CloneableFnWithArg<Arg>: FnOnce(Arg) {
|
||||
fn clone_box(&self) -> Box<dyn CloneableFnWithArg<Arg>>;
|
||||
}
|
||||
|
||||
impl<F, Arg> CloneableFnWithArg<Arg> for F
|
||||
where
|
||||
F: FnOnce(Arg) + Clone + 'static,
|
||||
{
|
||||
fn clone_box(&self) -> Box<dyn CloneableFnWithArg<Arg>> {
|
||||
Box::new(self.clone())
|
||||
}
|
||||
}
|
||||
|
||||
impl<Arg> Clone for Box<dyn CloneableFnWithArg<Arg>> {
|
||||
fn clone(&self) -> Self {
|
||||
(**self).clone_box()
|
||||
}
|
||||
}
|
||||
|
||||
impl<Arg> Default for Box<dyn CloneableFnWithArg<Arg>> {
|
||||
fn default() -> Self {
|
||||
Box::new(|_| {})
|
||||
}
|
||||
}
|
||||
|
||||
impl<Arg> Debug for Box<dyn CloneableFnWithArg<Arg>> {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
"Box<dyn CloneableFnWithArg<{}>>",
|
||||
std::any::type_name::<Arg>()
|
||||
)
|
||||
}
|
||||
}
|
|
@ -1,38 +0,0 @@
|
|||
use std::fmt::Debug;
|
||||
|
||||
pub trait CloneableFnWithArgAndReturn<Arg, R>: FnOnce(Arg) -> R {
|
||||
fn clone_box(&self) -> Box<dyn CloneableFnWithArgAndReturn<Arg, R>>;
|
||||
}
|
||||
|
||||
impl<F, R, Arg> CloneableFnWithArgAndReturn<Arg, R> for F
|
||||
where
|
||||
F: FnMut(Arg) -> R + Clone + 'static,
|
||||
R: 'static,
|
||||
{
|
||||
fn clone_box(&self) -> Box<dyn CloneableFnWithArgAndReturn<Arg, R>> {
|
||||
Box::new(self.clone())
|
||||
}
|
||||
}
|
||||
|
||||
impl<R, Arg> Clone for Box<dyn CloneableFnWithArgAndReturn<Arg, R>> {
|
||||
fn clone(&self) -> Self {
|
||||
(**self).clone_box()
|
||||
}
|
||||
}
|
||||
|
||||
impl<R: Default + 'static, Arg> Default for Box<dyn CloneableFnWithArgAndReturn<Arg, R>> {
|
||||
fn default() -> Self {
|
||||
Box::new(|_| Default::default())
|
||||
}
|
||||
}
|
||||
|
||||
impl<R, Arg> Debug for Box<dyn CloneableFnWithArgAndReturn<Arg, R>> {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
"Box<dyn CloneableFnWithArgAndReturn<{}, {}>>",
|
||||
std::any::type_name::<Arg>(),
|
||||
std::any::type_name::<R>()
|
||||
)
|
||||
}
|
||||
}
|
|
@ -1,37 +0,0 @@
|
|||
use std::fmt::Debug;
|
||||
|
||||
pub trait CloneableFnWithReturn<R>: FnOnce() -> R {
|
||||
fn clone_box(&self) -> Box<dyn CloneableFnWithReturn<R>>;
|
||||
}
|
||||
|
||||
impl<F, R> CloneableFnWithReturn<R> for F
|
||||
where
|
||||
F: FnOnce() -> R + Clone + 'static,
|
||||
R: 'static,
|
||||
{
|
||||
fn clone_box(&self) -> Box<dyn CloneableFnWithReturn<R>> {
|
||||
Box::new(self.clone())
|
||||
}
|
||||
}
|
||||
|
||||
impl<R> Clone for Box<dyn CloneableFnWithReturn<R>> {
|
||||
fn clone(&self) -> Self {
|
||||
(**self).clone_box()
|
||||
}
|
||||
}
|
||||
|
||||
impl<R: Default + 'static> Default for Box<dyn CloneableFnWithReturn<R>> {
|
||||
fn default() -> Self {
|
||||
Box::new(|| Default::default())
|
||||
}
|
||||
}
|
||||
|
||||
impl<R> Debug for Box<dyn CloneableFnWithReturn<R>> {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
"Box<dyn CloneableFnWithReturn<{}>>",
|
||||
std::any::type_name::<R>()
|
||||
)
|
||||
}
|
||||
}
|
|
@ -1,6 +1,5 @@
|
|||
#![cfg_attr(feature = "ssr", allow(unused_variables, unused_imports))]
|
||||
|
||||
use crate::utils::CloneableFnWithReturn;
|
||||
use cfg_if::cfg_if;
|
||||
use default_struct_builder::DefaultBuilder;
|
||||
use leptos::leptos_dom::helpers::TimeoutHandle;
|
||||
|
@ -20,7 +19,7 @@ pub struct DebounceOptions {
|
|||
pub fn debounce_filter<R>(
|
||||
ms: impl Into<MaybeSignal<f64>>,
|
||||
options: DebounceOptions,
|
||||
) -> impl Fn(Box<dyn CloneableFnWithReturn<R>>) -> Rc<RefCell<Option<R>>> + Clone
|
||||
) -> impl Fn(Rc<dyn Fn() -> R>) -> Rc<RefCell<Option<R>>> + Clone
|
||||
where
|
||||
R: 'static,
|
||||
{
|
||||
|
@ -38,7 +37,7 @@ where
|
|||
let ms = ms.into();
|
||||
let max_wait_signal = options.max_wait;
|
||||
|
||||
move |_invoke: Box<dyn CloneableFnWithReturn<R>>| {
|
||||
move |_invoke: Rc<dyn Fn() -> R>| {
|
||||
let duration = ms.get_untracked();
|
||||
let max_duration = max_wait_signal.get_untracked();
|
||||
|
||||
|
|
|
@ -4,40 +4,39 @@ mod throttle;
|
|||
pub use debounce::*;
|
||||
pub use throttle::*;
|
||||
|
||||
use crate::utils::{CloneableFnWithArgAndReturn, CloneableFnWithReturn};
|
||||
use leptos::MaybeSignal;
|
||||
use std::cell::RefCell;
|
||||
use std::rc::Rc;
|
||||
|
||||
macro_rules! BoxFilterFn {
|
||||
macro_rules! RcFilterFn {
|
||||
($R:ident) => {
|
||||
Box<dyn CloneableFnWithArgAndReturn<Box<dyn CloneableFnWithReturn<$R>>, Rc<RefCell<Option<$R>>>>>
|
||||
Rc<dyn Fn(Rc<dyn Fn() -> $R>) -> Rc<RefCell<Option<$R>>>>
|
||||
}
|
||||
}
|
||||
|
||||
pub fn create_filter_wrapper<F, R>(
|
||||
filter: BoxFilterFn!(R),
|
||||
filter: RcFilterFn!(R),
|
||||
func: F,
|
||||
) -> impl Fn() -> Rc<RefCell<Option<R>>> + Clone
|
||||
where
|
||||
F: FnOnce() -> R + Clone + 'static,
|
||||
F: Fn() -> R + Clone + 'static,
|
||||
R: 'static,
|
||||
{
|
||||
move || filter.clone()(Box::new(func.clone()))
|
||||
move || Rc::clone(&filter)(Rc::new(func.clone()))
|
||||
}
|
||||
|
||||
pub fn create_filter_wrapper_with_arg<F, Arg, R>(
|
||||
filter: BoxFilterFn!(R),
|
||||
filter: RcFilterFn!(R),
|
||||
func: F,
|
||||
) -> impl Fn(Arg) -> Rc<RefCell<Option<R>>> + Clone
|
||||
where
|
||||
F: FnOnce(Arg) -> R + Clone + 'static,
|
||||
F: Fn(Arg) -> R + Clone + 'static,
|
||||
R: 'static,
|
||||
Arg: Clone + 'static,
|
||||
{
|
||||
move |arg: Arg| {
|
||||
let func = func.clone();
|
||||
filter.clone()(Box::new(move || func(arg)))
|
||||
Rc::clone(&filter)(Rc::new(move || func(arg.clone())))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -57,16 +56,16 @@ pub enum FilterOptions {
|
|||
}
|
||||
|
||||
impl FilterOptions {
|
||||
pub fn filter_fn<R>(&self) -> BoxFilterFn!(R)
|
||||
pub fn filter_fn<R>(&self) -> RcFilterFn!(R)
|
||||
where
|
||||
R: 'static,
|
||||
{
|
||||
match self {
|
||||
FilterOptions::Debounce { ms, options } => Box::new(debounce_filter(*ms, *options)),
|
||||
FilterOptions::Throttle { ms, options } => Box::new(throttle_filter(*ms, *options)),
|
||||
FilterOptions::None => Box::new(|invoke: Box<dyn CloneableFnWithReturn<R>>| {
|
||||
Rc::new(RefCell::new(Some(invoke())))
|
||||
}),
|
||||
FilterOptions::Debounce { ms, options } => Rc::new(debounce_filter(*ms, *options)),
|
||||
FilterOptions::Throttle { ms, options } => Rc::new(throttle_filter(*ms, *options)),
|
||||
FilterOptions::None => {
|
||||
Rc::new(|invoke: Rc<dyn Fn() -> R>| Rc::new(RefCell::new(Some(invoke()))))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
#![cfg_attr(feature = "ssr", allow(unused_variables, unused_imports))]
|
||||
|
||||
use crate::utils::CloneableFnWithReturn;
|
||||
use cfg_if::cfg_if;
|
||||
use default_struct_builder::DefaultBuilder;
|
||||
use js_sys::Date;
|
||||
|
@ -31,7 +30,7 @@ impl Default for ThrottleOptions {
|
|||
pub fn throttle_filter<R>(
|
||||
ms: impl Into<MaybeSignal<f64>>,
|
||||
options: ThrottleOptions,
|
||||
) -> impl Fn(Box<dyn CloneableFnWithReturn<R>>) -> Rc<RefCell<Option<R>>> + Clone
|
||||
) -> impl Fn(Rc<dyn Fn() -> R>) -> Rc<RefCell<Option<R>>> + Clone
|
||||
where
|
||||
R: 'static,
|
||||
{
|
||||
|
@ -50,7 +49,7 @@ where
|
|||
|
||||
let ms = ms.into();
|
||||
|
||||
move |mut _invoke: Box<dyn CloneableFnWithReturn<R>>| {
|
||||
move |mut _invoke: Rc<dyn Fn() -> R>| {
|
||||
let duration = ms.get_untracked();
|
||||
let elapsed = Date::now() - last_exec.get();
|
||||
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
mod clonable_fn;
|
||||
mod filters;
|
||||
mod is;
|
||||
mod js_value_from_to_string;
|
||||
|
@ -6,7 +5,6 @@ mod pausable;
|
|||
mod signal_filtered;
|
||||
mod use_derive_signal;
|
||||
|
||||
pub use clonable_fn::*;
|
||||
pub use filters::*;
|
||||
pub use is::*;
|
||||
pub(crate) use js_value_from_to_string::*;
|
||||
|
|
Loading…
Add table
Reference in a new issue