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 std::{rc::Rc, str::FromStr};
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
use wasm_bindgen::JsValue;
|
use wasm_bindgen::JsValue;
|
||||||
use web_sys::Storage;
|
use web_sys::{Storage, Window};
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct UseStorageOptions<T, C: Codec<T>> {
|
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
|
where
|
||||||
T: Clone + Default + FromStr + PartialEq + ToString,
|
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.
|
/// 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>,
|
key: impl AsRef<str>,
|
||||||
options: UseStorageOptions<T, C>,
|
options: UseStorageOptions<T, C>,
|
||||||
) -> (Memo<T>, impl Fn(Option<T>) -> ())
|
) -> (Memo<T>, impl Fn(Option<T>) -> ())
|
||||||
|
@ -54,11 +117,22 @@ where
|
||||||
on_error,
|
on_error,
|
||||||
listen_to_storage_changes,
|
listen_to_storage_changes,
|
||||||
} = options;
|
} = 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
|
let initial_value = storage
|
||||||
.to_owned()
|
.to_owned()
|
||||||
// Get initial item from storage
|
// Pull from storage
|
||||||
.and_then(|s| {
|
.and_then(|s| {
|
||||||
let result = s
|
let result = s
|
||||||
.get_item(key.as_ref())
|
.get_item(key.as_ref())
|
||||||
|
@ -66,8 +140,9 @@ where
|
||||||
handle_error(&on_error, result)
|
handle_error(&on_error, result)
|
||||||
})
|
})
|
||||||
.unwrap_or_default();
|
.unwrap_or_default();
|
||||||
// Attempt to parse the item string
|
// Decode initial value
|
||||||
let initial_value = decode_item(&codec, initial_value, &on_error);
|
let initial_value = decode_item(&codec, initial_value, &on_error);
|
||||||
|
|
||||||
let (data, set_data) = create_signal(initial_value);
|
let (data, set_data) = create_signal(initial_value);
|
||||||
|
|
||||||
// Update storage value
|
// Update storage value
|
||||||
|
@ -130,15 +205,6 @@ where
|
||||||
(value, set_value)
|
(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.
|
/// 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>(
|
fn handle_error<T, Err>(
|
||||||
on_error: &Rc<dyn Fn(UseStorageError<Err>)>,
|
on_error: &Rc<dyn Fn(UseStorageError<Err>)>,
|
||||||
|
|
Loading…
Add table
Reference in a new issue