leptos_use/
use_timestamp.rs

1use crate::core::now;
2use crate::utils::Pausable;
3use crate::{
4    UseIntervalFnOptions, UseRafFnOptions, use_interval_fn_with_options, use_raf_fn_with_options,
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/// > Make sure you follow the [instructions in Server-Side Rendering](https://leptos-use.rs/server_side_rendering.html).
60///
61/// On the server this function will return a signal with the milliseconds since the Unix epoch.
62/// But the signal will never update (as there's no `request_animation_frame` on the server).
63pub fn use_timestamp() -> Signal<f64> {
64    use_timestamp_with_controls().timestamp
65}
66
67/// Version of [`use_timestamp`] that takes a `UseTimestampOptions`. See [`use_timestamp`] for how to use.
68pub fn use_timestamp_with_options(options: UseTimestampOptions) -> Signal<f64> {
69    use_timestamp_with_controls_and_options(options).timestamp
70}
71
72/// Version of [`use_timestamp`] that returns controls. See [`use_timestamp`] for how to use.
73pub fn use_timestamp_with_controls() -> UseTimestampReturn {
74    use_timestamp_with_controls_and_options(UseTimestampOptions::default())
75}
76
77/// Version of [`use_timestamp`] that takes a `UseTimestampOptions` and returns controls. See [`use_timestamp`] for how to use.
78pub fn use_timestamp_with_controls_and_options(options: UseTimestampOptions) -> UseTimestampReturn {
79    let UseTimestampOptions {
80        offset,
81        immediate,
82        interval,
83        callback,
84    } = options;
85
86    let (ts, set_ts) = signal(now() + offset);
87
88    let update = move || {
89        set_ts.set(now() + offset);
90    };
91
92    let cb = {
93        let callback = Rc::clone(&callback);
94
95        move || {
96            update();
97
98            #[cfg(debug_assertions)]
99            let _z = leptos::reactive::diagnostics::SpecialNonReactiveZone::enter();
100
101            callback(ts.get_untracked());
102        }
103    };
104
105    match interval {
106        TimestampInterval::RequestAnimationFrame => {
107            let Pausable {
108                pause,
109                resume,
110                is_active,
111            } = use_raf_fn_with_options(
112                move |_| cb(),
113                UseRafFnOptions::default().immediate(immediate),
114            );
115
116            UseTimestampReturn {
117                timestamp: ts.into(),
118                is_active,
119                pause: Arc::new(pause),
120                resume: Arc::new(resume),
121            }
122        }
123
124        TimestampInterval::Interval(interval) => {
125            let Pausable {
126                pause,
127                resume,
128                is_active,
129            } = use_interval_fn_with_options(
130                cb,
131                interval,
132                UseIntervalFnOptions::default().immediate(immediate),
133            );
134
135            UseTimestampReturn {
136                timestamp: ts.into(),
137                is_active,
138                pause: Arc::new(pause),
139                resume: Arc::new(resume),
140            }
141        }
142    }
143}
144
145/// Options for [`use_timestamp_with_controls_and_options`].
146#[derive(DefaultBuilder)]
147pub struct UseTimestampOptions {
148    /// Offset value in milliseconds that is added to the returned timestamp. Defaults to `0.0`.
149    offset: f64,
150
151    /// Whether to update the timestamp immediately. Defaults to `true`.
152    immediate: bool,
153
154    /// Update interval in milliseconds or `RequestAnimationFrame`. Defaults to `RequestAnimationFrame`.
155    #[builder(into)]
156    interval: TimestampInterval,
157
158    /// Callback to be called whenever the timestamp is updated.
159    callback: Rc<dyn Fn(f64)>,
160}
161
162/// Interval type for [`UseTimestampOptions`].
163#[derive(Copy, Clone, Eq, PartialEq, Debug)]
164pub enum TimestampInterval {
165    /// use [`fn@crate::use_raf_fn`] for updating the timestamp
166    RequestAnimationFrame,
167
168    /// use [`fn@crate::use_interval_fn`] for updating the timestamp
169    Interval(u64),
170}
171
172impl From<u64> for TimestampInterval {
173    fn from(value: u64) -> Self {
174        Self::Interval(value)
175    }
176}
177
178impl Default for UseTimestampOptions {
179    fn default() -> Self {
180        Self {
181            offset: 0.0,
182            immediate: true,
183            interval: TimestampInterval::RequestAnimationFrame,
184            callback: Rc::new(|_| {}),
185        }
186    }
187}
188
189/// Return type of [`use_timestamp_with_controls`].
190pub struct UseTimestampReturn {
191    /// The current timestamp
192    pub timestamp: Signal<f64>,
193
194    /// A Signal that indicates whether the timestamp updating is active. `false` when paused.
195    pub is_active: Signal<bool>,
196
197    /// Temporarily pause the timestamp from updating
198    pub pause: Arc<dyn Fn()>,
199
200    /// Resume the timestamp updating
201    pub resume: Arc<dyn Fn()>,
202}