diff options
Diffstat (limited to 'src/stores')
| -rw-r--r-- | src/stores/stateBin.ts | 88 |
1 files changed, 59 insertions, 29 deletions
diff --git a/src/stores/stateBin.ts b/src/stores/stateBin.ts index ca61ed77..3fd38a99 100644 --- a/src/stores/stateBin.ts +++ b/src/stores/stateBin.ts @@ -18,19 +18,26 @@ let state: StateBin = {}; let changedBeforeHydration = false; let initialEmission = true; let applyingStoredValue = false; +let hydrationPromise = Promise.resolve(); if (browser) { - localforage.getItem<StateBin>(STORAGE_KEY).then((value) => { - if (value && typeof value === "object" && !changedBeforeHydration) { - applyingStoredValue = true; - baseStore.set(value); - applyingStoredValue = false; - } + hydrationPromise = localforage + .getItem<StateBin>(STORAGE_KEY) + .then(async (value): Promise<void> => { + if (value && typeof value === "object") { + const nextState = changedBeforeHydration + ? { ...value, ...state } + : value; - hydrated = true; + applyingStoredValue = true; + baseStore.set(nextState); + applyingStoredValue = false; + } - localforage.setItem(STORAGE_KEY, state); - }); + hydrated = true; + + await localforage.setItem(STORAGE_KEY, state); + }); baseStore.subscribe((value) => { state = value; @@ -44,36 +51,59 @@ if (browser) { }); } +export const hydrateStateBin = () => hydrationPromise; + const createProxyStore = (store: Writable<StateBin>) => { - return new Proxy(store, { - get(target, prop: string) { - if (prop in target) - return (target as unknown as Record<string, unknown>)[prop]; + const keyStores = new Map< + string, + { + subscribe: (run: (value: StateBin[string]) => void) => () => void; + set: (value: StateBin[string]) => void; + update: (updater: (value: StateBin[string]) => StateBin[string]) => void; + } + >(); - const derivedKey = writable(get(store)[prop]); + const setKeyValue = (prop: string, value: StateBin[string]) => { + const state = get(store); + const updatedState = { ...state }; - derivedKey.subscribe((value) => { - const state = get(store); - const updatedState = { ...state }; + if (value === null || value === undefined) delete updatedState[prop]; + else updatedState[prop] = value; - if (value === null || value === undefined) delete updatedState[prop]; - else updatedState[prop] = value; + store.set(updatedState); + }; - store.set(updatedState); - }); + return new Proxy(store, { + get(target, prop: string | symbol) { + if (prop in target) return Reflect.get(target, prop); - return derivedKey; - }, + if (typeof prop !== "string") return undefined; + + const existingStore = keyStores.get(prop); - set(_, prop: string, value) { - const state = get(store); - const updatedState = { ...state }; + if (existingStore) return existingStore; - if (value === null || value === undefined) delete updatedState[prop]; - else updatedState[prop] = value; + const keyStore = { + subscribe(run: (value: StateBin[string]) => void) { + return store.subscribe((value) => run(value[prop])); + }, + set(value: StateBin[string]) { + setKeyValue(prop, value); + }, + update(updater: (value: StateBin[string]) => StateBin[string]) { + setKeyValue(prop, updater(get(store)[prop])); + }, + }; + + keyStores.set(prop, keyStore); + + return keyStore; + }, - store.set(updatedState); + set(_, prop: string | symbol, value) { + if (typeof prop !== "string") return false; + setKeyValue(prop, value); return true; }, }); |