mirror of
https://github.com/adoyle0/leptos-use.git
synced 2025-02-02 10:54:15 -05:00
Problem: only local storage is available. Provide session and generic web_sys::Storage fns
This commit is contained in:
parent
c6d9ea28e5
commit
0fb4f7e6a1
1 changed files with 81 additions and 15 deletions
|
@ -3,7 +3,7 @@ use leptos::*;
|
|||
use std::{rc::Rc, str::FromStr};
|
||||
use thiserror::Error;
|
||||
use wasm_bindgen::JsValue;
|
||||
use web_sys::Storage;
|
||||
use web_sys::{Storage, Window};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct UseStorageOptions<T, C: Codec<T>> {
|
||||
|
@ -36,11 +36,74 @@ pub fn use_local_storage<T>(key: impl AsRef<str>) -> (Memo<T>, impl Fn(Option<T>
|
|||
where
|
||||
T: Clone + Default + FromStr + PartialEq + ToString,
|
||||
{
|
||||
use_local_storage_with_options(key, UseStorageOptions::string_codec())
|
||||
use_storage_with_options(get_local_storage, key, UseStorageOptions::string_codec())
|
||||
}
|
||||
|
||||
pub fn use_local_storage_with_options<T, C>(
|
||||
key: impl AsRef<str>,
|
||||
options: UseStorageOptions<T, C>,
|
||||
) -> (Memo<T>, impl Fn(Option<T>) -> ())
|
||||
where
|
||||
T: Clone + Default + PartialEq,
|
||||
C: Codec<T>,
|
||||
{
|
||||
use_storage_with_options(|w| w.local_storage(), key, options)
|
||||
}
|
||||
|
||||
fn get_local_storage(w: &Window) -> Result<Option<web_sys::Storage>, JsValue> {
|
||||
w.local_storage()
|
||||
}
|
||||
|
||||
/// Hook for using session storage. Returns a result of a signal and a setter / deleter.
|
||||
pub fn use_session_storage<T>(key: impl AsRef<str>) -> (Memo<T>, impl Fn(Option<T>) -> ())
|
||||
where
|
||||
T: Clone + Default + FromStr + PartialEq + ToString,
|
||||
{
|
||||
use_storage_with_options(get_session_storage, key, UseStorageOptions::string_codec())
|
||||
}
|
||||
|
||||
pub fn use_session_storage_with_options<T, C>(
|
||||
key: impl AsRef<str>,
|
||||
options: UseStorageOptions<T, C>,
|
||||
) -> (Memo<T>, impl Fn(Option<T>) -> ())
|
||||
where
|
||||
T: Clone + Default + PartialEq,
|
||||
C: Codec<T>,
|
||||
{
|
||||
use_storage_with_options(get_session_storage, key, options)
|
||||
}
|
||||
|
||||
fn get_session_storage(w: &Window) -> Result<Option<web_sys::Storage>, JsValue> {
|
||||
w.session_storage()
|
||||
}
|
||||
|
||||
/// Hook for using custom storage. Returns a result of a signal and a setter / deleter.
|
||||
pub fn use_custom_storage<T>(
|
||||
storage: impl Into<web_sys::Storage>,
|
||||
key: impl AsRef<str>,
|
||||
) -> (Memo<T>, impl Fn(Option<T>) -> ())
|
||||
where
|
||||
T: Clone + Default + FromStr + PartialEq + ToString,
|
||||
{
|
||||
use_custom_storage_with_options(storage, key, UseStorageOptions::string_codec())
|
||||
}
|
||||
|
||||
pub fn use_custom_storage_with_options<T, C>(
|
||||
storage: impl Into<web_sys::Storage>,
|
||||
key: impl AsRef<str>,
|
||||
options: UseStorageOptions<T, C>,
|
||||
) -> (Memo<T>, impl Fn(Option<T>) -> ())
|
||||
where
|
||||
T: Clone + Default + PartialEq,
|
||||
C: Codec<T>,
|
||||
{
|
||||
let storage = storage.into();
|
||||
use_storage_with_options(|_| Ok(Some(storage)), key, options)
|
||||
}
|
||||
|
||||
/// Hook for using local storage. Returns a result of a signal and a setter / deleter.
|
||||
pub fn use_local_storage_with_options<T, C>(
|
||||
fn use_storage_with_options<T, C>(
|
||||
get_storage: impl FnOnce(&Window) -> Result<Option<web_sys::Storage>, JsValue>,
|
||||
key: impl AsRef<str>,
|
||||
options: UseStorageOptions<T, C>,
|
||||
) -> (Memo<T>, impl Fn(Option<T>) -> ())
|
||||
|
@ -54,11 +117,22 @@ where
|
|||
on_error,
|
||||
listen_to_storage_changes,
|
||||
} = options;
|
||||
let storage: Result<Storage, ()> = handle_error(&on_error, try_storage());
|
||||
|
||||
// Get storage API
|
||||
let storage = use_window()
|
||||
.as_ref()
|
||||
.ok_or(UseStorageError::WindowReturnedNone)
|
||||
.and_then(|w| {
|
||||
get_storage(w)
|
||||
.map_err(UseStorageError::StorageNotAvailable)
|
||||
.and_then(|s| s.ok_or(UseStorageError::StorageReturnedNone))
|
||||
});
|
||||
let storage: Result<Storage, ()> = handle_error(&on_error, storage);
|
||||
|
||||
// Fetch initial value (undecoded)
|
||||
let initial_value = storage
|
||||
.to_owned()
|
||||
// Get initial item from storage
|
||||
// Pull from storage
|
||||
.and_then(|s| {
|
||||
let result = s
|
||||
.get_item(key.as_ref())
|
||||
|
@ -66,8 +140,9 @@ where
|
|||
handle_error(&on_error, result)
|
||||
})
|
||||
.unwrap_or_default();
|
||||
// Attempt to parse the item string
|
||||
// Decode initial value
|
||||
let initial_value = decode_item(&codec, initial_value, &on_error);
|
||||
|
||||
let (data, set_data) = create_signal(initial_value);
|
||||
|
||||
// Update storage value
|
||||
|
@ -130,15 +205,6 @@ where
|
|||
(value, set_value)
|
||||
}
|
||||
|
||||
fn try_storage<Err>() -> Result<Storage, UseStorageError<Err>> {
|
||||
use_window()
|
||||
.as_ref()
|
||||
.ok_or_else(|| UseStorageError::WindowReturnedNone)?
|
||||
.local_storage()
|
||||
.map_err(|err| UseStorageError::StorageNotAvailable(err))?
|
||||
.ok_or_else(|| UseStorageError::StorageReturnedNone)
|
||||
}
|
||||
|
||||
/// Calls the on_error callback with the given error. Removes the error from the Result to avoid double error handling.
|
||||
fn handle_error<T, Err>(
|
||||
on_error: &Rc<dyn Fn(UseStorageError<Err>)>,
|
||||
|
|
Loading…
Add table
Reference in a new issue