{"version":3,"file":"create-storage.mjs","names":[],"sources":["../../src/use-local-storage/create-storage.ts"],"sourcesContent":["/* oxlint-disable no-console */\nimport { useCallback, useEffect, useState } from 'react';\nimport { useWindowEvent } from '../use-window-event/use-window-event';\n\nexport type StorageType = 'localStorage' | 'sessionStorage';\n\nexport interface UseStorageOptions<T> {\n  /** Storage key */\n  key: string;\n\n  /** Default value that will be set if value is not found in storage */\n  defaultValue?: T;\n\n  /** If set to true, value will be updated in useEffect after mount. Default value is true. */\n  getInitialValueInEffect?: boolean;\n\n  /** Determines whether the value must be synced between browser tabs, `true` by default */\n  sync?: boolean;\n\n  /** Function to serialize value into string to be save in storage */\n  serialize?: (value: T) => string;\n\n  /** Function to deserialize string value from storage to value */\n  deserialize?: (value: string | undefined) => T;\n}\n\nfunction serializeJSON<T>(value: T, hookName: string = 'use-local-storage') {\n  try {\n    return JSON.stringify(value);\n  } catch (error) {\n    throw new Error(`@mantine/hooks ${hookName}: Failed to serialize the value`);\n  }\n}\n\nfunction deserializeJSON(value: string | undefined) {\n  try {\n    return value && JSON.parse(value);\n  } catch {\n    return value;\n  }\n}\n\nfunction createStorageHandler(type: StorageType) {\n  const getItem = (key: string) => {\n    try {\n      return window[type].getItem(key);\n    } catch (error) {\n      console.warn('use-local-storage: Failed to get value from storage, localStorage is blocked');\n      return null;\n    }\n  };\n\n  const setItem = (key: string, value: string) => {\n    try {\n      window[type].setItem(key, value);\n    } catch (error) {\n      console.warn('use-local-storage: Failed to set value to storage, localStorage is blocked');\n    }\n  };\n\n  const removeItem = (key: string) => {\n    try {\n      window[type].removeItem(key);\n    } catch (error) {\n      console.warn(\n        'use-local-storage: Failed to remove value from storage, localStorage is blocked'\n      );\n    }\n  };\n\n  return { getItem, setItem, removeItem };\n}\n\nexport type UseStorageReturnValue<T> = [\n  T, // current value\n  (val: T | ((prevState: T) => T)) => void, // callback to set value in storage\n  () => void, // callback to remove value from storage\n];\n\nexport function createStorage<T>(type: StorageType, hookName: string) {\n  const eventName = type === 'localStorage' ? 'mantine-local-storage' : 'mantine-session-storage';\n  const { getItem, setItem, removeItem } = createStorageHandler(type);\n\n  return function useStorage({\n    key,\n    defaultValue,\n    getInitialValueInEffect = true,\n    sync = true,\n    deserialize = deserializeJSON,\n    serialize = (value: T) => serializeJSON(value, hookName),\n  }: UseStorageOptions<T>): UseStorageReturnValue<T> {\n    const readStorageValue = useCallback(\n      (skipStorage?: boolean): T => {\n        let storageBlockedOrSkipped;\n\n        try {\n          storageBlockedOrSkipped =\n            typeof window === 'undefined' ||\n            !(type in window) ||\n            window[type] === null ||\n            !!skipStorage;\n        } catch (_e) {\n          storageBlockedOrSkipped = true;\n        }\n\n        if (storageBlockedOrSkipped) {\n          return defaultValue as T;\n        }\n\n        const storageValue = getItem(key);\n        return storageValue !== null ? deserialize(storageValue) : (defaultValue as T);\n      },\n      [key, defaultValue]\n    );\n\n    const [value, setValue] = useState<T>(readStorageValue(getInitialValueInEffect));\n\n    const setStorageValue = useCallback(\n      (val: T | ((prevState: T) => T)) => {\n        if (val instanceof Function) {\n          setValue((current) => {\n            const result = val(current);\n            setItem(key, serialize(result));\n            // Defer dispatching this event to avoid the handler being called during render.\n            queueMicrotask(() => {\n              window.dispatchEvent(\n                new CustomEvent(eventName, { detail: { key, value: val(current) } })\n              );\n            });\n            return result;\n          });\n        } else {\n          setItem(key, serialize(val));\n          window.dispatchEvent(new CustomEvent(eventName, { detail: { key, value: val } }));\n          setValue(val);\n        }\n      },\n      [key]\n    );\n\n    const removeStorageValue = useCallback(() => {\n      removeItem(key);\n      setValue(defaultValue as T);\n      window.dispatchEvent(new CustomEvent(eventName, { detail: { key, value: defaultValue } }));\n    }, [key, defaultValue]);\n\n    useWindowEvent('storage', (event) => {\n      if (sync) {\n        if (event.storageArea === window[type] && event.key === key) {\n          setValue(deserialize(event.newValue ?? undefined));\n        }\n      }\n    });\n\n    useWindowEvent(eventName, (event) => {\n      if (sync) {\n        if (event.detail.key === key) {\n          setValue(event.detail.value);\n        }\n      }\n    });\n\n    useEffect(() => {\n      if (defaultValue !== undefined && value === undefined) {\n        setStorageValue(defaultValue);\n      }\n    }, [defaultValue, value, setStorageValue]);\n\n    useEffect(() => {\n      const val = readStorageValue();\n      val !== undefined && setStorageValue(val);\n    }, [key]);\n\n    return [value === undefined ? (defaultValue as T) : value, setStorageValue, removeStorageValue];\n  };\n}\n\nexport function readValue(type: StorageType) {\n  const { getItem } = createStorageHandler(type);\n\n  return function read<T>({\n    key,\n    defaultValue,\n    deserialize = deserializeJSON,\n  }: UseStorageOptions<T>) {\n    let storageBlockedOrSkipped;\n\n    try {\n      storageBlockedOrSkipped =\n        typeof window === 'undefined' || !(type in window) || window[type] === null;\n    } catch (_e) {\n      storageBlockedOrSkipped = true;\n    }\n\n    if (storageBlockedOrSkipped) {\n      return defaultValue as T;\n    }\n\n    const storageValue = getItem(key);\n    return storageValue !== null ? deserialize(storageValue) : (defaultValue as T);\n  };\n}\n"],"mappings":"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"}