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}