leptos_use/
use_timestamp.rs

1use crate::core::now;
2use crate::utils::Pausable;
3use crate::{
4    use_interval_fn_with_options, use_raf_fn_with_options, UseIntervalFnOptions, UseRafFnOptions,
5};
6use default_struct_builder::DefaultBuilder;
7use leptos::prelude::*;
8use leptos::reactive::wrappers::read::Signal;
9use std::rc::Rc;
10use std::sync::Arc;
11
12/// Reactive current timestamp.
13///
14/// ## Demo
15///
16/// [Link to Demo](https://github.com/Synphonyte/leptos-use/tree/main/examples/use_timestamp)
17///
18/// ## Usage
19///
20/// ```
21/// # use leptos::prelude::*;
22/// # use leptos_use::use_timestamp;
23/// #
24/// # #[component]
25/// # fn Demo() -> impl IntoView {
26/// let timestamp = use_timestamp();
27/// #
28/// # view! { }
29/// # }
30/// ```
31///
32/// With controls:
33///
34/// ```
35/// # use leptos::prelude::*;
36/// # use leptos_use::{use_timestamp_with_controls, UseTimestampReturn};
37/// #
38/// # #[component]
39/// # fn Demo() -> impl IntoView {
40/// let UseTimestampReturn {
41///     timestamp,
42///     is_active,
43///     pause,
44///     resume,
45/// } = use_timestamp_with_controls();
46/// #
47/// # view! { }
48/// # }
49/// ```
50///
51/// ## SendWrapped Return
52///
53/// The returned closures `pause` and `resume` of the `..._with_controls` versions are
54/// sendwrapped functions. They can only be called from the same thread that called
55/// `use_timestamp_with_controls`.
56///
57/// ## Server-Side Rendering
58///
59/// On the server this function will return a signal with the milliseconds since the Unix epoch.
60/// But the signal will never update (as there's no `request_animation_frame` on the server).
61pub fn use_timestamp() -> Signal<f64> {
62    use_timestamp_with_controls().timestamp
63}
64
65/// Version of [`use_timestamp`] that takes a `UseTimestampOptions`. See [`use_timestamp`] for how to use.
66pub fn use_timestamp_with_options(options: UseTimestampOptions) -> Signal<f64> {
67    use_timestamp_with_controls_and_options(options).timestamp
68}
69
70/// Version of [`use_timestamp`] that returns controls. See [`use_timestamp`] for how to use.
71pub fn use_timestamp_with_controls() -> UseTimestampReturn {
72    use_timestamp_with_controls_and_options(UseTimestampOptions::default())
73}
74
75/// Version of [`use_timestamp`] that takes a `UseTimestampOptions` and returns controls. See [`use_timestamp`] for how to use.
76pub fn use_timestamp_with_controls_and_options(options: UseTimestampOptions) -> UseTimestampReturn {
77    let UseTimestampOptions {
78        offset,
79        immediate,
80        interval,
81        callback,
82    } = options;
83
84    let (ts, set_ts) = signal(now() + offset);
85
86    let update = move || {
87        set_ts.set(now() + offset);
88    };
89
90    let cb = {
91        let callback = Rc::clone(&callback);
92
93        move || {
94            update();
95
96            #[cfg(debug_assertions)]
97            let _z = leptos::reactive::diagnostics::SpecialNonReactiveZone::enter();
98
99            callback(ts.get_untracked());
100        }
101    };
102
103    match interval {
104        TimestampInterval::RequestAnimationFrame => {
105            let Pausable {
106                pause,
107                resume,
108                is_active,
109            } = use_raf_fn_with_options(
110                move |_| cb(),
111                UseRafFnOptions::default().immediate(immediate),
112            );
113
114            UseTimestampReturn {
115                timestamp: ts.into(),
116                is_active,
117                pause: Arc::new(pause),
118                resume: Arc::new(resume),
119            }
120        }
121
122        TimestampInterval::Interval(interval) => {
123            let Pausable {
124                pause,
125                resume,
126                is_active,
127            } = use_interval_fn_with_options(
128                cb,
129                interval,
130                UseIntervalFnOptions::default().immediate(immediate),
131            );
132
133            UseTimestampReturn {
134                timestamp: ts.into(),
135                is_active,
136                pause: Arc::new(pause),
137                resume: Arc::new(resume),
138            }
139        }
140    }
141}
142
143/// Options for [`use_timestamp_with_controls_and_options`].
144#[derive(DefaultBuilder)]
145pub struct UseTimestampOptions {
146    /// Offset value in milliseconds that is added to the returned timestamp. Defaults to `0.0`.
147    offset: f64,
148
149    /// Whether to update the timestamp immediately. Defaults to `true`.
150    immediate: bool,
151
152    /// Update interval in milliseconds or `RequestAnimationFrame`. Defaults to `RequestAnimationFrame`.
153    #[builder(into)]
154    interval: TimestampInterval,
155
156    /// Callback to be called whenever the timestamp is updated.
157    callback: Rc<dyn Fn(f64)>,
158}
159
160/// Interval type for [`UseTimestampOptions`].
161#[derive(Copy, Clone, Eq, PartialEq, Debug)]
162pub enum TimestampInterval {
163    /// use [`fn@crate::use_raf_fn`] for updating the timestamp
164    RequestAnimationFrame,
165
166    /// use [`fn@crate::use_interval_fn`] for updating the timestamp
167    Interval(u64),
168}
169
170impl From<u64> for TimestampInterval {
171    fn from(value: u64) -> Self {
172        Self::Interval(value)
173    }
174}
175
176impl Default for UseTimestampOptions {
177    fn default() -> Self {
178        Self {
179            offset: 0.0,
180            immediate: true,
181            interval: TimestampInterval::RequestAnimationFrame,
182            callback: Rc::new(|_| {}),
183        }
184    }
185}
186
187/// Return type of [`use_timestamp_with_controls`].
188pub struct UseTimestampReturn {
189    /// The current timestamp
190    pub timestamp: Signal<f64>,
191
192    /// A Signal that indicates whether the timestamp updating is active. `false` when paused.
193    pub is_active: Signal<bool>,
194
195    /// Temporarily pause the timestamp from updating
196    pub pause: Arc<dyn Fn()>,
197
198    /// Resume the timestamp updating
199    pub resume: Arc<dyn Fn()>,
200}