aboutsummaryrefslogtreecommitdiff
path: root/packages/web-util/src/hooks/useLocalStorage.ts
diff options
context:
space:
mode:
Diffstat (limited to 'packages/web-util/src/hooks/useLocalStorage.ts')
-rw-r--r--packages/web-util/src/hooks/useLocalStorage.ts70
1 files changed, 39 insertions, 31 deletions
diff --git a/packages/web-util/src/hooks/useLocalStorage.ts b/packages/web-util/src/hooks/useLocalStorage.ts
index 55efd01cb..45b7abd3c 100644
--- a/packages/web-util/src/hooks/useLocalStorage.ts
+++ b/packages/web-util/src/hooks/useLocalStorage.ts
@@ -19,7 +19,7 @@
* @author Sebastian Javier Marchano (sebasjm)
*/
-import { Codec } from "@gnu-taler/taler-util";
+import { Codec, codecForString } from "@gnu-taler/taler-util";
import { useEffect, useState } from "preact/hooks";
import {
ObservableMap,
@@ -28,7 +28,26 @@ import {
memoryMap,
} from "../utils/observable.js";
-export interface LocalStorageState<Type = string> {
+declare const opaque_StorageKey: unique symbol;
+
+export type StorageKey<Key> = {
+ id: string;
+ [opaque_StorageKey]: true;
+ codec: Codec<Key>;
+};
+
+export function buildStorageKey<Key = string>(
+ name: string,
+ codec?: Codec<Key>,
+): StorageKey<Key> {
+ return {
+ id: name,
+ codec: codec ?? (codecForString() as Codec<Key>),
+ [opaque_StorageKey]: true,
+ };
+}
+
+export interface StorageState<Type = string> {
value?: Type;
update: (s: Type) => void;
reset: () => void;
@@ -50,59 +69,48 @@ const storage: ObservableMap<string, string> = (function buildStorage() {
//with initial value
export function useLocalStorage<Type = string>(
- key: string,
- options?: {
- defaultValue: Type;
- codec?: Codec<Type>;
- },
-): Required<LocalStorageState<Type>>;
+ key: StorageKey<Type>,
+ defaultValue: Type,
+): Required<StorageState<Type>>;
//without initial value
export function useLocalStorage<Type = string>(
- key: string,
- options?: {
- codec?: Codec<Type>;
- },
-): LocalStorageState<Type>;
+ key: StorageKey<Type>,
+): StorageState<Type>;
// impl
export function useLocalStorage<Type = string>(
- key: string,
- options?: {
- defaultValue?: Type;
- codec?: Codec<Type>;
- },
-): LocalStorageState<Type> {
+ key: StorageKey<Type>,
+ defaultValue?: Type,
+): StorageState<Type> {
function convert(updated: string | undefined): Type | undefined {
- if (updated === undefined) return options?.defaultValue; //optional
+ if (updated === undefined) return defaultValue; //optional
try {
- return !options?.codec
- ? (updated as Type)
- : options.codec.decode(JSON.parse(updated));
+ return key.codec.decode(JSON.parse(updated));
} catch (e) {
//decode error
- return options?.defaultValue;
+ return defaultValue;
}
}
const [storedValue, setStoredValue] = useState<Type | undefined>(
(): Type | undefined => {
- const prev = storage.get(key);
+ const prev = storage.get(key.id);
return convert(prev);
},
);
useEffect(() => {
- return storage.onUpdate(key, () => {
- const newValue = storage.get(key);
+ return storage.onUpdate(key.id, () => {
+ const newValue = storage.get(key.id);
setStoredValue(convert(newValue));
});
}, []);
const setValue = (value?: Type): void => {
if (value === undefined) {
- storage.delete(key);
+ storage.delete(key.id);
} else {
storage.set(
- key,
- options?.codec ? JSON.stringify(value) : (value as string),
+ key.id,
+ key.codec ? JSON.stringify(value) : (value as string),
);
}
};
@@ -111,7 +119,7 @@ export function useLocalStorage<Type = string>(
value: storedValue,
update: setValue,
reset: () => {
- setValue(options?.defaultValue);
+ setValue(defaultValue);
},
};
}