use-session-storage-state
Advanced tools
Comparing version 18.2.0 to 19.0.0
@@ -1,4 +0,4 @@ | ||
import useSessionStorageState from './src/useSessionStorageState'; | ||
import type { SessionStorageOptions, SessionStorageState } from './src/useSessionStorageState'; | ||
import useSessionStorageState from './src/useSessionStorageState.js'; | ||
import type { SessionStorageOptions, SessionStorageState } from './src/useSessionStorageState.js'; | ||
export default useSessionStorageState; | ||
export type { SessionStorageOptions, SessionStorageState }; |
@@ -1,7 +0,2 @@ | ||
"use strict"; | ||
var __importDefault = (this && this.__importDefault) || function (mod) { | ||
return (mod && mod.__esModule) ? mod : { "default": mod }; | ||
}; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
const useSessionStorageState_1 = __importDefault(require("./src/useSessionStorageState")); | ||
exports.default = useSessionStorageState_1.default; | ||
import useSessionStorageState from './src/useSessionStorageState.js'; | ||
export default useSessionStorageState; |
{ | ||
"name": "use-session-storage-state", | ||
"version": "18.2.0", | ||
"version": "19.0.0", | ||
"description": "React hook that persist data in sessionStorage", | ||
"license": "MIT", | ||
"repository": "astoilkov/use-session-storage-state", | ||
"repository": { | ||
"type": "git", | ||
"url": "git+https://github.com/astoilkov/use-session-storage-state.git" | ||
}, | ||
"funding": "https://github.com/sponsors/astoilkov", | ||
@@ -25,22 +28,24 @@ "homepage": "https://github.com/astoilkov/use-session-storage-state", | ||
], | ||
"module": "es/index.js", | ||
"jsnext:main": "es/index.js", | ||
"type": "module", | ||
"exports": { | ||
"types": "./index.d.ts", | ||
"default": "./index.js" | ||
}, | ||
"sideEffects": false, | ||
"scripts": { | ||
"build": "tsc && tsc --project tsconfig.esm.json", | ||
"size": "yarn run build && size-limit", | ||
"build": "tsc", | ||
"size": "yarn build && size-limit", | ||
"lint": "eslint --cache --format=pretty --ext=.ts ./", | ||
"test": "yarn run build && yarn run lint && if [[ -z $CI ]]; then jest --coverage --coverageReporters=text; else jest --coverage; fi", | ||
"release": "yarn run build && np", | ||
"test": "yarn build && yarn lint && vitest --run", | ||
"release": "yarn build && np", | ||
"prettier": "prettier --write --config .prettierrc.yaml {*.ts,*.json}" | ||
}, | ||
"engines": { | ||
"node": ">=12" | ||
"node": ">=14" | ||
}, | ||
"files": [ | ||
"index.js", | ||
"src/*.js", | ||
"index.d.ts", | ||
"src/*.d.ts", | ||
"es/**/*.js" | ||
"src/**/*.js", | ||
"src/**/*.d.ts" | ||
], | ||
@@ -52,28 +57,27 @@ "peerDependencies": { | ||
"devDependencies": { | ||
"@size-limit/preset-small-lib": "^7.0.8", | ||
"@testing-library/react": "^13.3.0", | ||
"@types/jest": "^28.1.1", | ||
"@types/react": "^18.0.12", | ||
"@types/react-dom": "^18.0.4", | ||
"@typescript-eslint/eslint-plugin": "^5.27.1", | ||
"@typescript-eslint/parser": "^5.27.1", | ||
"@size-limit/preset-small-lib": "^11.1.1", | ||
"@testing-library/react": "^14.0.0", | ||
"@types/react": "^18.2.67", | ||
"@types/react-dom": "^18.2.22", | ||
"@typescript-eslint/eslint-plugin": "^7.2.0", | ||
"@typescript-eslint/parser": "^7.2.0", | ||
"@vitest/coverage-v8": "^1.4.0", | ||
"confusing-browser-globals": "^1.0.11", | ||
"eslint": "^8.17.0", | ||
"eslint-config-strictest": "^0.4.0", | ||
"eslint-formatter-pretty": "^4.0.0", | ||
"eslint": "^8.21.0", | ||
"eslint-config-strictest": "^0.8.1", | ||
"eslint-formatter-pretty": "^5.0.0", | ||
"eslint-plugin-promise": "^6.0.0", | ||
"eslint-plugin-react": "^7.29.4", | ||
"eslint-plugin-react-hooks": "^4.5.0", | ||
"eslint-plugin-unicorn": "^42.0.0", | ||
"jest": "^28.1.1", | ||
"jest-environment-jsdom": "^28.1.1", | ||
"np": "^7.6.1", | ||
"prettier": "^2.6.2", | ||
"react": "^18.1.0", | ||
"react-dom": "^18.1.0", | ||
"eslint-plugin-unicorn": "^43.0.2", | ||
"jsdom": "^22.1.0", | ||
"np": "^7.6.3", | ||
"prettier": "^3.2.5", | ||
"react": "^18.2.0", | ||
"react-dom": "^18.2.0", | ||
"react-test-renderer": "^18.1.0", | ||
"size-limit": "^7.0.8", | ||
"superjson": "^1.9.1", | ||
"ts-jest": "^28.0.4", | ||
"typescript": "^4.7.3" | ||
"size-limit": "^11.1.1", | ||
"superjson": "^2.2.1", | ||
"typescript": "^5.4.2", | ||
"vitest": "^1.4.0" | ||
}, | ||
@@ -83,9 +87,9 @@ "size-limit": [ | ||
"name": "import *", | ||
"path": "es/index.js", | ||
"path": "index.js", | ||
"limit": "1.75 kB", | ||
"gzip": false | ||
"brotli": false | ||
}, | ||
{ | ||
"name": "import *", | ||
"path": "es/index.js", | ||
"path": "index.js", | ||
"limit": "800 B" | ||
@@ -92,0 +96,0 @@ } |
@@ -7,3 +7,2 @@ # `use-session-storage-state` | ||
[![Gzipped Size](https://img.shields.io/bundlephobia/minzip/use-session-storage-state)](https://bundlephobia.com/result?p=use-session-storage-state) | ||
[![Test Coverage](https://img.shields.io/codeclimate/coverage/astoilkov/use-session-storage-state)](https://codeclimate.com/github/astoilkov/use-session-storage-state/test_coverage) | ||
[![Build Status](https://img.shields.io/github/actions/workflow/status/astoilkov/use-session-storage-state/main.yml?branch=main)](https://github.com/astoilkov/use-session-storage-state/actions/workflows/main.yml) | ||
@@ -25,5 +24,5 @@ | ||
- Clone of [`use-local-storage-state`](https://github.com/astoilkov/use-local-storage-state) that I've been [maintaining for the past 2 years](https://github.com/astoilkov/use-local-storage-state/graphs/contributors). | ||
- React 18 concurrent rendering support. | ||
- Clone of [`use-local-storage-state`](https://github.com/astoilkov/use-local-storage-state) that I've been [actively maintaining for the past 4 years](https://github.com/astoilkov/use-local-storage-state/graphs/contributors). | ||
- SSR support. | ||
- Works with concurrent rendering and React 19. | ||
- Handles the `Window` [`storage`](https://developer.mozilla.org/en-US/docs/Web/API/Window/storage_event) event and updates changes across iframe's. Disable with `storageSync: false`. | ||
@@ -30,0 +29,0 @@ - In-memory fallback when `sessionStorage` throws an error and can't store the data. Provides a `isPersistent` API to let you notify the user their data isn't currently being stored. |
import type { Dispatch, SetStateAction } from 'react'; | ||
export declare const inMemoryData: Map<string, unknown>; | ||
export declare type SessionStorageOptions<T> = { | ||
export type SessionStorageOptions<T> = { | ||
defaultValue?: T | (() => T); | ||
@@ -11,3 +11,3 @@ storageSync?: boolean; | ||
}; | ||
export declare type SessionStorageState<T> = [ | ||
export type SessionStorageState<T> = [ | ||
T, | ||
@@ -20,4 +20,4 @@ Dispatch<SetStateAction<T>>, | ||
]; | ||
export default function useSessionStorageState(key: string, options?: Omit<SessionStorageOptions<unknown>, 'defaultValue'>): SessionStorageState<unknown>; | ||
export default function useSessionStorageState(key: string, options?: SessionStorageOptions<undefined>): SessionStorageState<unknown>; | ||
export default function useSessionStorageState<T>(key: string, options?: Omit<SessionStorageOptions<T | undefined>, 'defaultValue'>): SessionStorageState<T | undefined>; | ||
export default function useSessionStorageState<T>(key: string, options?: SessionStorageOptions<T>): SessionStorageState<T>; |
@@ -1,55 +0,20 @@ | ||
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.inMemoryData = void 0; | ||
const react_1 = require("react"); | ||
// in memory fallback used then `sessionStorage` throws an error | ||
exports.inMemoryData = new Map(); | ||
function useSessionStorageState(key, options) { | ||
const [defaultValue] = (0, react_1.useState)(options === null || options === void 0 ? void 0 : options.defaultValue); | ||
// SSR support | ||
// - on the server, return a constant value | ||
// - this makes the implementation simpler and smaller because the `sessionStorage` object is | ||
// `undefined` on the server | ||
if (typeof window === 'undefined') { | ||
return [ | ||
defaultValue, | ||
() => { }, | ||
{ | ||
isPersistent: true, | ||
removeItem: () => { }, | ||
}, | ||
]; | ||
} | ||
import { useCallback, useEffect, useMemo, useRef, useState, useSyncExternalStore } from 'react'; | ||
// in memory fallback used when `sessionStorage` throws an error | ||
export const inMemoryData = new Map(); | ||
export default function useSessionStorageState(key, options) { | ||
const serializer = options === null || options === void 0 ? void 0 : options.serializer; | ||
// disabling ESLint because the above if statement can be executed only on the server. the value | ||
// of `window` can't change between calls. | ||
// eslint-disable-next-line react-hooks/rules-of-hooks | ||
const [defaultValue] = useState(options === null || options === void 0 ? void 0 : options.defaultValue); | ||
return useBrowserSessionStorageState(key, defaultValue, options === null || options === void 0 ? void 0 : options.storageSync, serializer === null || serializer === void 0 ? void 0 : serializer.parse, serializer === null || serializer === void 0 ? void 0 : serializer.stringify); | ||
} | ||
exports.default = useSessionStorageState; | ||
function useBrowserSessionStorageState(key, defaultValue, storageSync = true, parse = parseJSON, stringify = JSON.stringify) { | ||
// store default value in sessionStorage: | ||
// - initial issue: https://github.com/astoilkov/use-local-storage-state/issues/26 | ||
// issues that were caused by incorrect initial and secondary implementations: | ||
// - https://github.com/astoilkov/use-local-storage-state/issues/30 | ||
// - https://github.com/astoilkov/use-local-storage-state/issues/33 | ||
if (!exports.inMemoryData.has(key) && | ||
defaultValue !== undefined && | ||
goodTry(() => sessionStorage.getItem(key)) === null) { | ||
// reasons for `sessionStorage` to throw an error: | ||
// - maximum quota is exceeded | ||
// - under Mobile Safari (since iOS 5) when the user enters private mode | ||
// `sessionStorage.setItem()` will throw | ||
// - trying to access sessionStorage object when cookies are disabled in Safari throws | ||
// "SecurityError: The operation is insecure." | ||
goodTry(() => sessionStorage.setItem(key, stringify(defaultValue))); | ||
} | ||
// we keep the `parsed` value in a ref because `useSyncExternalStore` requires a cached version | ||
const storageValue = (0, react_1.useRef)({ | ||
item: null, | ||
parsed: defaultValue, | ||
const storageItem = useRef({ | ||
string: null, | ||
parsed: undefined, | ||
}); | ||
const value = (0, react_1.useSyncExternalStore)((0, react_1.useCallback)((onStoreChange) => { | ||
const onChange = (localKey) => { | ||
if (key === localKey) { | ||
const value = useSyncExternalStore( | ||
// useSyncExternalStore.subscribe | ||
useCallback((onStoreChange) => { | ||
const onChange = (sessionKey) => { | ||
if (key === sessionKey) { | ||
onStoreChange(); | ||
@@ -63,16 +28,13 @@ } | ||
}, [key]), | ||
// eslint-disable-next-line react-hooks/exhaustive-deps | ||
// useSyncExternalStore.getSnapshot | ||
() => { | ||
var _a; | ||
const item = (_a = goodTry(() => sessionStorage.getItem(key))) !== null && _a !== void 0 ? _a : null; | ||
if (exports.inMemoryData.has(key)) { | ||
storageValue.current = { | ||
item, | ||
parsed: exports.inMemoryData.get(key), | ||
}; | ||
const string = (_a = goodTry(() => sessionStorage.getItem(key))) !== null && _a !== void 0 ? _a : null; | ||
if (inMemoryData.has(key)) { | ||
storageItem.current.parsed = inMemoryData.get(key); | ||
} | ||
else if (item !== storageValue.current.item) { | ||
else if (string !== storageItem.current.string) { | ||
let parsed; | ||
try { | ||
parsed = item === null ? defaultValue : parse(item); | ||
parsed = string === null ? defaultValue : parse(string); | ||
} | ||
@@ -82,13 +44,30 @@ catch (_b) { | ||
} | ||
storageValue.current = { | ||
item, | ||
parsed, | ||
}; | ||
storageItem.current.parsed = parsed; | ||
} | ||
return storageValue.current.parsed; | ||
storageItem.current.string = string; | ||
// store default value in sessionStorage: | ||
// - initial issue: https://github.com/astoilkov/use-local-storage-state/issues/26 | ||
// issues that were caused by incorrect initial and secondary implementations: | ||
// - https://github.com/astoilkov/use-local-storage-state/issues/30 | ||
// - https://github.com/astoilkov/use-local-storage-state/issues/33 | ||
if (string === null && defaultValue !== undefined) { | ||
// reasons for `sessionStorage` to throw an error: | ||
// - maximum quota is exceeded | ||
// - under Mobile Safari (since iOS 5) when the user enters private mode | ||
// `sessionStorage.setItem()` will throw | ||
// - trying to access sessionStorage object when cookies are disabled in Safari throws | ||
// "SecurityError: The operation is insecure." | ||
// eslint-disable-next-line no-console | ||
goodTry(() => { | ||
const string = stringify(defaultValue); | ||
sessionStorage.setItem(key, string); | ||
storageItem.current = { string, parsed: defaultValue }; | ||
}); | ||
} | ||
return storageItem.current.parsed; | ||
}, | ||
// istanbul ignore next | ||
// useSyncExternalStore.getServerSnapshot | ||
() => defaultValue); | ||
const setState = (0, react_1.useCallback)((newValue) => { | ||
const value = newValue instanceof Function ? newValue(storageValue.current.parsed) : newValue; | ||
const setState = useCallback((newValue) => { | ||
const value = newValue instanceof Function ? newValue(storageItem.current.parsed) : newValue; | ||
// reasons for `sessionStorage` to throw an error: | ||
@@ -102,6 +81,6 @@ // - maximum quota is exceeded | ||
sessionStorage.setItem(key, stringify(value)); | ||
exports.inMemoryData.delete(key); | ||
inMemoryData.delete(key); | ||
} | ||
catch (_a) { | ||
exports.inMemoryData.set(key, value); | ||
inMemoryData.set(key, value); | ||
} | ||
@@ -113,3 +92,3 @@ triggerCallbacks(key); | ||
// triggered the change | ||
(0, react_1.useEffect)(() => { | ||
useEffect(() => { | ||
if (!storageSync) { | ||
@@ -126,10 +105,10 @@ return undefined; | ||
}, [key, storageSync]); | ||
return (0, react_1.useMemo)(() => [ | ||
return useMemo(() => [ | ||
value, | ||
setState, | ||
{ | ||
isPersistent: value === defaultValue || !exports.inMemoryData.has(key), | ||
isPersistent: value === defaultValue || !inMemoryData.has(key), | ||
removeItem() { | ||
goodTry(() => sessionStorage.removeItem(key)); | ||
exports.inMemoryData.delete(key); | ||
inMemoryData.delete(key); | ||
triggerCallbacks(key); | ||
@@ -156,5 +135,3 @@ }, | ||
} | ||
catch (_a) { | ||
return undefined; | ||
} | ||
catch (_a) { } | ||
} |
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
No repository
Supply chain riskPackage does not have a linked source code repository. Without this field, a package will have no reference to the location of the source code use to generate the package.
Found 1 instance in 1 package
25
0
Yes
17664
7
158
189
1