{"version":3,"file":"use-local-storage.cjs","names":[],"sources":["../../src/hooks/use-local-storage.ts"],"sourcesContent":["import { useCallback, useEffect, useState } from \"react\";\n\nexport type LocalStorageOptions<T> = {\n    serialize?: (value: T) => string;\n    deserialize?: (raw: string) => T;\n};\n\nconst defaultSerialize = JSON.stringify;\nconst defaultDeserialize = <T>(raw: string): T => JSON.parse(raw) as T;\n\n/**\n * State synced with `localStorage`. SSR-safe — initial render returns the\n * provided default; the stored value is hydrated after mount. Updates to the\n * same key in other tabs are picked up via the `storage` event.\n *\n * @tempest-limits empty-catch — the three swallows here are the hook's contract.\n * A write that hits the quota (or Safari private mode) still updates React state,\n * so the session keeps working and only persistence is lost; a `storage` event\n * carrying a value this tab cannot deserialize is another tab's bug, and the\n * useful response is to keep the value already rendered rather than tear the\n * component down over a foreign write.\n *\n * @param key - localStorage key.\n * @param defaultValue - value used when nothing is stored or in SSR.\n * @param options - custom `serialize` / `deserialize` (default JSON).\n * @returns Tuple `[value, setValue, remove]`.\n */\nexport function useLocalStorage<T>(\n    key: string,\n    defaultValue: T,\n    options: LocalStorageOptions<T> = {},\n): [T, (value: T | ((prev: T) => T)) => void, () => void] {\n    const serialize = options.serialize ?? defaultSerialize;\n    const deserialize = options.deserialize ?? defaultDeserialize;\n\n    const read = useCallback((): T => {\n        if (typeof window === \"undefined\") return defaultValue;\n        try {\n            const raw = window.localStorage.getItem(key);\n            if (raw === null) return defaultValue;\n            return deserialize(raw);\n        } catch {\n            return defaultValue;\n        }\n    }, [key, defaultValue, deserialize]);\n\n    const [value, setStored] = useState<T>(read);\n\n    useEffect(() => {\n        setStored(read());\n    }, [read]);\n\n    const setValue = useCallback(\n        (next: T | ((prev: T) => T)): void => {\n            setStored((current) => {\n                const resolved =\n                    typeof next === \"function\" ? (next as (prev: T) => T)(current) : next;\n                try {\n                    if (typeof window !== \"undefined\") {\n                        window.localStorage.setItem(key, serialize(resolved));\n                    }\n                } catch {\n                    /* empty */\n                }\n                return resolved;\n            });\n        },\n        [key, serialize],\n    );\n\n    const remove = useCallback((): void => {\n        try {\n            if (typeof window !== \"undefined\") {\n                window.localStorage.removeItem(key);\n            }\n        } catch {\n            /* empty */\n        }\n        setStored(defaultValue);\n    }, [key, defaultValue]);\n\n    useEffect(() => {\n        if (typeof window === \"undefined\") return;\n        const onStorage = (event: StorageEvent): void => {\n            if (event.key !== key) return;\n            if (event.newValue === null) {\n                setStored(defaultValue);\n                return;\n            }\n            try {\n                setStored(deserialize(event.newValue));\n            } catch {\n                /* empty */\n            }\n        };\n        window.addEventListener(\"storage\", onStorage);\n        return () => window.removeEventListener(\"storage\", onStorage);\n    }, [key, defaultValue, deserialize]);\n\n    return [value, setValue, remove];\n}\n"],"mappings":"uBAOA,IAAM,EAAmB,KAAK,UACxB,EAAyB,GAAmB,KAAK,MAAM,CAAG,EAmBhE,SAAgB,EACZ,EACA,EACA,EAAkC,CAAC,EACmB,CACtD,IAAM,EAAY,EAAQ,WAAa,EACjC,EAAc,EAAQ,aAAe,EAErC,GAAA,EAAO,EAAA,YAAA,KAAqB,CAC9B,GAAI,OAAO,OAAW,IAAa,OAAO,EAC1C,GAAI,CACA,IAAM,EAAM,OAAO,aAAa,QAAQ,CAAG,EAE3C,OADI,IAAQ,KAAa,EAClB,EAAY,CAAG,CAC1B,MAAQ,CACJ,OAAO,CACX,CACJ,EAAG,CAAC,EAAK,EAAc,CAAW,CAAC,EAE7B,CAAC,EAAO,IAAA,EAAa,EAAA,SAAA,CAAY,CAAI,GAE3C,EAAA,EAAA,UAAA,KAAgB,CACZ,EAAU,EAAK,CAAC,CACpB,EAAG,CAAC,CAAI,CAAC,EAET,IAAM,GAAA,EAAW,EAAA,YAAA,CACZ,GAAqC,CAClC,EAAW,GAAY,CACnB,IAAM,EACF,OAAO,GAAS,WAAc,EAAwB,CAAO,EAAI,EACrE,GAAI,CACI,OAAO,OAAW,KAClB,OAAO,aAAa,QAAQ,EAAK,EAAU,CAAQ,CAAC,CAE5D,MAAQ,CAER,CACA,OAAO,CACX,CAAC,CACL,EACA,CAAC,EAAK,CAAS,CACnB,EAEM,GAAA,EAAS,EAAA,YAAA,KAAwB,CACnC,GAAI,CACI,OAAO,OAAW,KAClB,OAAO,aAAa,WAAW,CAAG,CAE1C,MAAQ,CAER,CACA,EAAU,CAAY,CAC1B,EAAG,CAAC,EAAK,CAAY,CAAC,EAoBtB,OAlBA,EAAA,EAAA,UAAA,KAAgB,CACZ,GAAI,OAAO,OAAW,IAAa,OACnC,IAAM,EAAa,GAA8B,CACzC,KAAM,MAAQ,EAClB,IAAI,EAAM,WAAa,KAAM,CACzB,EAAU,CAAY,EACtB,MACJ,CACA,GAAI,CACA,EAAU,EAAY,EAAM,QAAQ,CAAC,CACzC,MAAQ,CAER,CALA,CAMJ,EAEA,OADA,OAAO,iBAAiB,UAAW,CAAS,MAC/B,OAAO,oBAAoB,UAAW,CAAS,CAChE,EAAG,CAAC,EAAK,EAAc,CAAW,CAAC,EAE5B,CAAC,EAAO,EAAU,CAAM,CACnC"}