use crate::hooks::use_signal::{Signal, use_signal};
use std::time::{Duration, Instant};
pub fn use_debounce<T>(value: T, delay: Duration) -> T
where
T: Clone + PartialEq + Send + Sync + 'static,
{
let debounced = use_signal(|| value.clone());
let last_value = use_signal(|| value.clone());
let last_change = use_signal(Instant::now);
let current_last: T = last_value.get();
if current_last != value {
last_value.set(value.clone());
last_change.set(Instant::now());
}
let current_debounced: T = debounced.get();
let current_last: T = last_value.get();
if last_change.get().elapsed() >= delay && current_debounced != current_last {
debounced.set(current_last);
}
debounced.get()
}
#[derive(Clone)]
pub struct DebounceHandle {
pending: Signal<bool>,
last_trigger: Signal<Instant>,
delay: Duration,
}
impl DebounceHandle {
pub fn trigger(&self) {
self.pending.set(true);
self.last_trigger.set(Instant::now());
}
pub fn is_ready(&self) -> bool {
self.pending.get() && self.last_trigger.get().elapsed() >= self.delay
}
pub fn reset(&self) {
self.pending.set(false);
}
pub fn is_pending(&self) -> bool {
self.pending.get()
}
}
pub fn use_debounce_handle(delay: Duration) -> DebounceHandle {
let pending = use_signal(|| false);
let last_trigger = use_signal(Instant::now);
DebounceHandle {
pending,
last_trigger,
delay,
}
}
pub fn use_throttle<T>(value: T, interval: Duration) -> T
where
T: Clone + Send + Sync + 'static,
{
let throttled = use_signal(|| value.clone());
let last_update = use_signal(Instant::now);
if last_update.get().elapsed() >= interval {
throttled.set(value);
last_update.set(Instant::now());
}
throttled.get()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_use_debounce_compiles() {
fn _test() {
let _debounced = use_debounce("test".to_string(), Duration::from_millis(300));
}
}
#[test]
fn test_use_throttle_compiles() {
fn _test() {
let _throttled = use_throttle(42, Duration::from_millis(100));
}
}
#[test]
fn test_debounce_handle_compiles() {
fn _test() {
let handle = use_debounce_handle(Duration::from_millis(300));
handle.trigger();
let _ = handle.is_ready();
handle.reset();
}
}
}