leptos_use/utils/filters/
debounce.rs1#![cfg_attr(feature = "ssr", allow(unused_variables, unused_imports))]
2
3use cfg_if::cfg_if;
4use default_struct_builder::DefaultBuilder;
5use leptos::leptos_dom::helpers::TimeoutHandle;
6use leptos::prelude::*;
7use std::sync::{Arc, Mutex};
8use std::time::Duration;
9
10#[derive(Copy, Clone, DefaultBuilder, Default)]
11pub struct DebounceOptions {
12 #[builder(into)]
15 pub max_wait: Signal<Option<f64>>,
16}
17
18pub fn debounce_filter<R>(
19 ms: impl Into<Signal<f64>>,
20 options: DebounceOptions,
21) -> impl Fn(Arc<dyn Fn() -> R>) -> Arc<Mutex<Option<R>>> + Clone
22where
23 R: 'static,
24{
25 let timer = Arc::new(Mutex::new(None::<TimeoutHandle>));
26 let max_timer = Arc::new(Mutex::new(None::<TimeoutHandle>));
27 let last_return_value: Arc<Mutex<Option<R>>> = Arc::new(Mutex::new(None));
28
29 let clear_timeout = move |timer: &Arc<Mutex<Option<TimeoutHandle>>>| {
30 let mut timer = timer.lock().unwrap();
31 if let Some(handle) = *timer {
32 handle.clear();
33 *timer = None;
34 }
35 };
36
37 on_cleanup({
38 let timer = Arc::clone(&timer);
39
40 move || {
41 clear_timeout(&timer);
42 }
43 });
44
45 let ms = ms.into();
46 let max_wait_signal = options.max_wait;
47
48 move |_invoke: Arc<dyn Fn() -> R>| {
49 let duration = ms.get_untracked();
50 let max_duration = max_wait_signal.get_untracked();
51
52 let last_return_val = Arc::clone(&last_return_value);
53 let invoke = move || {
54 #[cfg(debug_assertions)]
55 let zone = leptos::reactive::diagnostics::SpecialNonReactiveZone::enter();
56
57 let return_value = _invoke();
58
59 #[cfg(debug_assertions)]
60 drop(zone);
61
62 let mut val_mut = last_return_val.lock().unwrap();
63 *val_mut = Some(return_value);
64 };
65
66 clear_timeout(&timer);
67
68 if duration <= 0.0 || max_duration.is_some_and(|d| d <= 0.0) {
69 clear_timeout(&max_timer);
70
71 invoke();
72 return Arc::clone(&last_return_value);
73 }
74
75 cfg_if! { if #[cfg(not(feature = "ssr"))] {
76 if let Some(max_duration) = max_duration {
78 let mut max_timer = max_timer.lock().unwrap();
79
80 if max_timer.is_none() {
81 let timer = Arc::clone(&timer);
82 let invok = invoke.clone();
83 *max_timer = set_timeout_with_handle(
84 move || {
85 clear_timeout(&timer);
86 invok();
87 },
88 Duration::from_millis(max_duration as u64),
89 )
90 .ok();
91 }
92 }
93
94 let max_timer = Arc::clone(&max_timer);
95
96 *timer.lock().unwrap() = set_timeout_with_handle(
98 move || {
99 clear_timeout(&max_timer);
100 invoke();
101 },
102 Duration::from_millis(duration as u64),
103 )
104 .ok();
105 }}
106
107 Arc::clone(&last_return_value)
108 }
109}