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}