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 let max_timer = Arc::clone(&max_timer);
40
41 move || {
42 clear_timeout(&timer);
43 clear_timeout(&max_timer);
44 }
45 });
46
47 let ms = ms.into();
48 let max_wait_signal = options.max_wait;
49
50 move |_invoke: Arc<dyn Fn() -> R>| {
51 let duration = ms.get_untracked();
52 let max_duration = max_wait_signal.get_untracked();
53
54 let last_return_val = Arc::clone(&last_return_value);
55 let invoke = move || {
56 #[cfg(debug_assertions)]
57 let zone = leptos::reactive::diagnostics::SpecialNonReactiveZone::enter();
58
59 let return_value = _invoke();
60
61 #[cfg(debug_assertions)]
62 drop(zone);
63
64 let mut val_mut = last_return_val.lock().unwrap();
65 *val_mut = Some(return_value);
66 };
67
68 clear_timeout(&timer);
69
70 if duration <= 0.0 || max_duration.is_some_and(|d| d <= 0.0) {
71 clear_timeout(&max_timer);
72
73 invoke();
74 return Arc::clone(&last_return_value);
75 }
76
77 cfg_if! { if #[cfg(not(feature = "ssr"))] {
78 if let Some(max_duration) = max_duration {
80 let max_timer_slot = Arc::clone(&max_timer);
81 let mut max_timer = max_timer.lock().unwrap();
82
83 if max_timer.is_none() {
84 let timer = Arc::clone(&timer);
85 let invok = invoke.clone();
86 *max_timer = set_timeout_with_handle(
87 move || {
88 clear_timeout(&timer);
89 *max_timer_slot.lock().unwrap() = None;
94 invok();
95 },
96 Duration::from_millis((max_duration as u64).min(i32::MAX as u64)),
97 )
98 .ok();
99 }
100 }
101
102 let max_timer = Arc::clone(&max_timer);
103
104 *timer.lock().unwrap() = set_timeout_with_handle(
106 move || {
107 clear_timeout(&max_timer);
108 invoke();
109 },
110 Duration::from_millis((duration as u64).min(i32::MAX as u64)),
111 )
112 .ok();
113 }}
114
115 Arc::clone(&last_return_value)
116 }
117}