Skip to main content

leptos_use_storage/
options.rs

1use crate::{MaybeRwSignal, NoFilter};
2use codee::CodecError;
3use leptos::prelude::*;
4use std::sync::Arc;
5use thiserror::Error;
6use wasm_bindgen::JsValue;
7
8/// Session handling errors returned by [`use_storage_with_options`](crate::use_storage_with_options).
9#[derive(Error, Debug)]
10pub enum UseStorageError<E, D> {
11    #[error("storage not available")]
12    StorageNotAvailable(JsValue),
13    #[error("storage not returned from window")]
14    StorageReturnedNone,
15    #[error("failed to get item")]
16    GetItemFailed(JsValue),
17    #[error("failed to set item")]
18    SetItemFailed(JsValue),
19    #[error("failed to delete item")]
20    RemoveItemFailed(JsValue),
21    #[error("failed to notify item changed")]
22    NotifyItemChangedFailed(JsValue),
23    #[error("failed to encode / decode item value")]
24    ItemCodecError(CodecError<E, D>),
25}
26
27/// Options for use with [`fn@crate::use_local_storage_with_options`], [`fn@crate::use_session_storage_with_options`] and [`use_storage_with_options`](crate::use_storage_with_options).
28/// Options for [`fn@crate::use_storage_with_options`].
29///
30/// The filter is a type parameter so that the debounce and throttle code is only compiled into
31/// your app if you use it.
32pub struct UseStorageOptions<T, E, D, F = NoFilter>
33where
34    T: Send + Sync + 'static,
35{
36    // Callback for when an error occurs
37    pub(crate) on_error: Arc<dyn Fn(UseStorageError<E, D>) + Send + Sync>,
38    // Whether to continuously listen to changes from browser storage
39    pub(crate) listen_to_storage_changes: bool,
40    // Initial value to use when the storage key is not set
41    pub(crate) initial_value: MaybeRwSignal<T>,
42    // Debounce or throttle the writing to storage whenever the value changes
43    pub(crate) filter: F,
44    /// Delays the reading of the value from storage by one animation frame during hydration.
45    /// This ensures that during hydration the value is the initial value just like it is on the server
46    /// which helps prevent hydration errors. Defaults to `false`.
47    pub(crate) delay_during_hydration: bool,
48}
49
50impl<T: Default, E, D> Default for UseStorageOptions<T, E, D>
51where
52    T: Send + Sync + 'static,
53{
54    fn default() -> Self {
55        Self {
56            on_error: Arc::new(|_err| ()),
57            listen_to_storage_changes: true,
58            initial_value: MaybeRwSignal::default(),
59            filter: NoFilter,
60            delay_during_hydration: false,
61        }
62    }
63}
64
65impl<T, E, D, F> UseStorageOptions<T, E, D, F>
66where
67    T: Send + Sync + 'static,
68{
69    /// Optional callback whenever an error occurs.
70    pub fn on_error(
71        self,
72        on_error: impl Fn(UseStorageError<E, D>) + Send + Sync + 'static,
73    ) -> Self {
74        Self {
75            on_error: Arc::new(on_error),
76            ..self
77        }
78    }
79
80    /// Whether to continuously listen to changes from browser storage. Defaults to `true`.
81    pub fn listen_to_storage_changes(self, listen_to_storage_changes: bool) -> Self {
82        Self {
83            listen_to_storage_changes,
84            ..self
85        }
86    }
87
88    /// Initial value to use when the storage key is not set. Note that this value is read once on creation of the storage hook and not updated again. Accepts a signal and defaults to `T::default()`.
89    pub fn initial_value(self, initial: impl Into<MaybeRwSignal<T>>) -> Self {
90        Self {
91            initial_value: initial.into(),
92            ..self
93        }
94    }
95
96    /// Debounce or throttle the writing to storage whenever the value changes with a
97    /// [`FilterOptions`](crate::FilterOptions). Defaults to no filter.
98    pub fn filter<NewF>(self, filter: NewF) -> UseStorageOptions<T, E, D, NewF> {
99        UseStorageOptions {
100            on_error: self.on_error,
101            listen_to_storage_changes: self.listen_to_storage_changes,
102            initial_value: self.initial_value,
103            filter,
104            delay_during_hydration: self.delay_during_hydration,
105        }
106    }
107
108    /// Delays the reading of the value from storage by one animation frame during hydration.
109    /// This ensures that during hydration the value is the initial value just like it is on the server
110    /// which helps prevent hydration errors. Defaults to `false`.
111    pub fn delay_during_hydration(self, delay_during_hydration: bool) -> Self {
112        Self {
113            delay_during_hydration,
114            ..self
115        }
116    }
117}