react-wire-persisted 2.1.0 → 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +121 -28
- package/dist/index.d.ts +197 -0
- package/dist/index.js +238 -339
- package/dist/react-wire-persisted.js +238 -339
- package/dist/react-wire-persisted.js.map +1 -0
- package/dist/react-wire-persisted.umd.cjs +2 -1
- package/dist/react-wire-persisted.umd.cjs.map +1 -0
- package/package.json +32 -23
- package/src/components/{HydrationProvider.jsx → HydrationProvider.tsx} +12 -2
- package/src/components/index.tsx +1 -0
- package/src/global.d.ts +16 -0
- package/src/hooks/{useHydration.js → useHydration.ts} +8 -3
- package/src/index.ts +9 -0
- package/src/providers/{LocalStorageProvider.js → LocalStorageProvider.ts} +35 -34
- package/src/providers/MemoryStorageProvider.ts +14 -0
- package/src/providers/{StorageProvider.js → RWPStorageProvider.ts} +30 -19
- package/src/{react-wire-persisted.js → react-wire-persisted.ts} +43 -47
- package/src/types.ts +19 -0
- package/src/utils/fakeLocalStorage.ts +17 -0
- package/src/utils/{index.js → index.ts} +4 -4
- package/src/utils/{isomorphic.js → isomorphic.ts} +8 -8
- package/src/utils/keys.ts +49 -0
- package/src/components/HydrationProvider.js +0 -45
- package/src/components/index.js +0 -1
- package/src/index.js +0 -6
- package/src/providers/MemoryStorageProvider.js +0 -14
- package/src/utils/fakeLocalStorage.js +0 -15
- package/src/utils/keys.js +0 -46
package/README.md
CHANGED
|
@@ -5,23 +5,13 @@
|
|
|
5
5
|
## Install
|
|
6
6
|
|
|
7
7
|
```shell
|
|
8
|
-
$ pnpm add
|
|
9
|
-
```
|
|
10
|
-
|
|
11
|
-
## Building
|
|
12
|
-
|
|
13
|
-
```shell
|
|
14
|
-
$ pnpm build
|
|
15
|
-
$ npm version patch # patch, minor, major
|
|
16
|
-
$ git push
|
|
17
|
-
$ git push --tags
|
|
18
|
-
$ npm publish
|
|
8
|
+
$ pnpm add @forminator/react-wire react-wire-persisted
|
|
19
9
|
```
|
|
20
10
|
|
|
21
11
|
## Usage
|
|
22
12
|
|
|
23
|
-
```
|
|
24
|
-
// constants.
|
|
13
|
+
```typescript
|
|
14
|
+
// constants.ts
|
|
25
15
|
import { key, getPrefixedKeys } from 'react-wire-persisted/lib/utils'
|
|
26
16
|
|
|
27
17
|
export const NS = 'myapp'
|
|
@@ -33,36 +23,48 @@ const prefixedKeys = getPrefixedKeys(NS)
|
|
|
33
23
|
export { prefixedKeys as keys }
|
|
34
24
|
```
|
|
35
25
|
|
|
36
|
-
```
|
|
37
|
-
// index.
|
|
26
|
+
```tsx
|
|
27
|
+
// index.tsx
|
|
38
28
|
import { NS } from './constants'
|
|
39
|
-
import * as
|
|
29
|
+
import * as rwp from 'react-wire-persisted'
|
|
30
|
+
|
|
31
|
+
rwp.setNamespace(NS)
|
|
40
32
|
|
|
41
|
-
|
|
33
|
+
rwp.setOptions({
|
|
34
|
+
logging: {
|
|
35
|
+
enabled: true,
|
|
36
|
+
},
|
|
37
|
+
storageProvider: rwp.MemoryStorageProvider,
|
|
38
|
+
})
|
|
42
39
|
|
|
43
40
|
// Normal React init code
|
|
44
41
|
```
|
|
45
42
|
|
|
46
|
-
```
|
|
47
|
-
// store.
|
|
43
|
+
```typescript
|
|
44
|
+
// store.ts
|
|
48
45
|
import { createPersistedWire } from 'react-wire-persisted'
|
|
49
46
|
import { keys } from './constants'
|
|
50
47
|
|
|
51
|
-
|
|
48
|
+
type User = {
|
|
49
|
+
id: number
|
|
50
|
+
email: string
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export const user = createPersistedWire<User | null>(keys.foo, null)
|
|
52
54
|
```
|
|
53
55
|
|
|
54
|
-
```
|
|
55
|
-
// SomeComponent.
|
|
56
|
+
```tsx
|
|
57
|
+
// SomeComponent.tsx
|
|
56
58
|
import { useWireState } from '@forminator/react-wire'
|
|
57
59
|
import * as store from './store'
|
|
58
60
|
|
|
59
61
|
const SomeComponent = () => {
|
|
60
|
-
const [
|
|
62
|
+
const [user, setUser] = useWireState(store.user)
|
|
61
63
|
return (
|
|
62
64
|
<div>
|
|
63
|
-
<p>
|
|
64
|
-
<button onClick={() =>
|
|
65
|
-
|
|
65
|
+
<p>User: {user?.email}</p>
|
|
66
|
+
<button onClick={() => setUser({ ...user, email: 'example@gmail.com'})}>
|
|
67
|
+
Change Email
|
|
66
68
|
</button>
|
|
67
69
|
</div>
|
|
68
70
|
)
|
|
@@ -75,9 +77,100 @@ See the [demo](demo) folder for a more complete example.
|
|
|
75
77
|
|
|
76
78
|
## Storage Providers
|
|
77
79
|
|
|
78
|
-
|
|
80
|
+
By default, this library uses `localStorage` via `LocalStorageProvider` in browser environments. However, you can customize the storage behavior using `setOptions`:
|
|
81
|
+
|
|
82
|
+
```typescript
|
|
83
|
+
import { setOptions, createPersistedWire } from 'react-wire-persisted'
|
|
84
|
+
import { MemoryStorageProvider } from 'react-wire-persisted'
|
|
85
|
+
|
|
86
|
+
// Use in-memory storage (useful for testing or SSR)
|
|
87
|
+
setOptions({
|
|
88
|
+
storageProvider: MemoryStorageProvider,
|
|
89
|
+
})
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
This is useful for:
|
|
93
|
+
- **Testing**: Avoid localStorage in unit tests
|
|
94
|
+
- **SSR**: Use in-memory storage during server-side rendering
|
|
95
|
+
- **Custom storage**: Implement your own provider by extending `RWPStorageProvider`
|
|
96
|
+
|
|
97
|
+
See [LocalStorageProvider](src/providers/LocalStorageProvider.ts) and [MemoryStorageProvider](src/providers/MemoryStorageProvider.ts) for implementation examples.
|
|
98
|
+
|
|
99
|
+
## API
|
|
100
|
+
|
|
101
|
+
### `createPersistedWire<T = null>(key: string, value?: T): PersistedWire<T>`
|
|
102
|
+
|
|
103
|
+
Creates a persisted Wire that automatically syncs with the configured storage provider.
|
|
104
|
+
|
|
105
|
+
### `setNamespace(namespace: string): void`
|
|
106
|
+
|
|
107
|
+
Sets the namespace for storage keys. This prefixes all keys to avoid collisions.
|
|
108
|
+
|
|
109
|
+
### `setOptions(options: Partial<RWPOptions>): void`
|
|
110
|
+
|
|
111
|
+
Configure library options:
|
|
112
|
+
- `logging.enabled`: Enable/disable logging (default: `false`)
|
|
113
|
+
- `storageProvider`: Custom storage provider class
|
|
114
|
+
|
|
115
|
+
### `getOptions(): RWPOptions`
|
|
116
|
+
|
|
117
|
+
Get current options.
|
|
79
118
|
|
|
80
|
-
|
|
119
|
+
### `getNamespace(): string | null`
|
|
120
|
+
|
|
121
|
+
Get current namespace.
|
|
122
|
+
|
|
123
|
+
### `getStorage(): RWPStorageProvider`
|
|
124
|
+
|
|
125
|
+
Get the current storage provider instance.
|
|
126
|
+
|
|
127
|
+
### `upgradeStorage(): boolean`
|
|
128
|
+
|
|
129
|
+
Attempts to upgrade from fake storage (used during SSR) to real localStorage. Returns `true` if upgrade was successful. Call this after hydration in client-side code.
|
|
130
|
+
|
|
131
|
+
## Building
|
|
132
|
+
|
|
133
|
+
```shell
|
|
134
|
+
$ pnpm build
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
## Contributing
|
|
138
|
+
|
|
139
|
+
Contributions are welcome. Please feel free to submit a [GitHub Issue](https://github.com/forminator/react-wire-persisted/issues) or pull request.
|
|
140
|
+
|
|
141
|
+
### Development
|
|
142
|
+
|
|
143
|
+
```shell
|
|
144
|
+
# Install dependencies
|
|
145
|
+
pnpm install
|
|
146
|
+
|
|
147
|
+
# Run tests
|
|
148
|
+
pnpm test
|
|
149
|
+
|
|
150
|
+
# Run linter
|
|
151
|
+
pnpm lint
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
## Publishing
|
|
155
|
+
|
|
156
|
+
To publish a new version to npm:
|
|
157
|
+
|
|
158
|
+
```shell
|
|
159
|
+
# Build the project
|
|
160
|
+
pnpm build
|
|
161
|
+
|
|
162
|
+
# Bump version (choose one)
|
|
163
|
+
npm version patch # bug fixes (e.g., 2.1.0 -> 2.1.1)
|
|
164
|
+
npm version minor # new features (e.g., 2.1.0 -> 2.2.0)
|
|
165
|
+
npm version major # breaking changes (e.g., 2.1.0 -> 3.0.0)
|
|
166
|
+
|
|
167
|
+
# Push changes and tags
|
|
168
|
+
git push
|
|
169
|
+
git push --tags
|
|
170
|
+
|
|
171
|
+
# Publish to npm
|
|
172
|
+
npm publish
|
|
173
|
+
```
|
|
81
174
|
|
|
82
175
|
## Miscellaneous
|
|
83
176
|
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
import { ReactNode } from 'react';
|
|
2
|
+
import * as utils from '@/utils';
|
|
3
|
+
import { Wire } from '@forminator/react-wire';
|
|
4
|
+
|
|
5
|
+
declare type AnyStorage = InternalStorage | Storage;
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Creates a persisted Wire using the `RWPStorageProvider` that is currently set
|
|
9
|
+
* Defaults to `localStorage` via `LocalStorageProvider`
|
|
10
|
+
*
|
|
11
|
+
* @param {String} key Unique key for storing this value
|
|
12
|
+
* @param {*} value Initial value of this Wire
|
|
13
|
+
* @returns A new Wire decorated with localStorage functionality
|
|
14
|
+
*/
|
|
15
|
+
export declare const createPersistedWire: <T = null>(key: string, value?: T) => PersistedWire<T>;
|
|
16
|
+
|
|
17
|
+
export declare const defaultOptions: RWPOptions;
|
|
18
|
+
|
|
19
|
+
export declare const getNamespace: () => string | null;
|
|
20
|
+
|
|
21
|
+
export declare const getOptions: () => RWPOptions;
|
|
22
|
+
|
|
23
|
+
export declare const getStorage: () => RWPStorageProvider;
|
|
24
|
+
|
|
25
|
+
export declare const HydrationProvider: ({ children, onUpgrade, autoUpgrade }: HydrationProviderProps) => ReactNode;
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* A Next.js App Router compatible component that handles automatic storage upgrade
|
|
29
|
+
* after hydration. Use this in your root layout.
|
|
30
|
+
*
|
|
31
|
+
* @param {Object} props Component props
|
|
32
|
+
* @param {React.ReactNode} props.children Child components to render
|
|
33
|
+
* @param {Function} props.onUpgrade Callback called when storage is upgraded
|
|
34
|
+
* @param {Boolean} props.autoUpgrade Whether to automatically upgrade storage (default: true)
|
|
35
|
+
*/
|
|
36
|
+
declare type HydrationProviderProps = {
|
|
37
|
+
children: ReactNode;
|
|
38
|
+
onUpgrade?: () => void;
|
|
39
|
+
autoUpgrade?: boolean;
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
declare interface InternalStorage {
|
|
43
|
+
getItem: (key: string) => string | null;
|
|
44
|
+
setItem: (key: string, value: string) => void;
|
|
45
|
+
removeItem: (key: string) => void;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* A storage provider for `localStorage`
|
|
50
|
+
* @see `RWPStorageProvider.ts` for documentation
|
|
51
|
+
*/
|
|
52
|
+
export declare class LocalStorageProvider extends RWPStorageProvider {
|
|
53
|
+
storage: AnyStorage;
|
|
54
|
+
private _isUsingFakeStorage;
|
|
55
|
+
constructor(namespace: string, registry?: Record<string, unknown>);
|
|
56
|
+
getStorage(): AnyStorage;
|
|
57
|
+
setNamespace(namespace: string): void;
|
|
58
|
+
getItem(key: string): any;
|
|
59
|
+
setItem(key: string, value: unknown): void;
|
|
60
|
+
removeItem(key: string, fromRegistry?: boolean): void;
|
|
61
|
+
getAll(): Record<string, unknown>;
|
|
62
|
+
_resetAll(useInitialValues?: boolean, excludedKeys?: string[], clearRegistry?: boolean): void;
|
|
63
|
+
resetAll(excludedKeys?: string[], clearRegistry?: boolean): void;
|
|
64
|
+
removeAll(excludedKeys?: string[], clearRegistry?: boolean): void;
|
|
65
|
+
/**
|
|
66
|
+
* Attempt to upgrade from fake storage to real localStorage
|
|
67
|
+
* This is useful for hydration scenarios
|
|
68
|
+
*/
|
|
69
|
+
upgradeToRealStorage(): boolean;
|
|
70
|
+
/**
|
|
71
|
+
* Check if currently using fake storage
|
|
72
|
+
*/
|
|
73
|
+
isUsingFakeStorage(): boolean;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export declare class MemoryStorageProvider extends LocalStorageProvider {
|
|
77
|
+
constructor(namespace: string, registry?: Record<string, unknown>);
|
|
78
|
+
getStorage(): InternalStorage;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
declare type PersistedWire<T> = Wire<T>;
|
|
82
|
+
|
|
83
|
+
declare type RWPOptions = {
|
|
84
|
+
logging: {
|
|
85
|
+
enabled: boolean;
|
|
86
|
+
};
|
|
87
|
+
storageProvider?: typeof RWPStorageProvider;
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Base class to allow storage access
|
|
92
|
+
* @see `LocalStorageProvider.ts` for an example implementation
|
|
93
|
+
*/
|
|
94
|
+
/** biome-ignore-all lint/correctness/noUnusedFunctionParameters: WIP next PR will switch to TypeScript */
|
|
95
|
+
export declare abstract class RWPStorageProvider {
|
|
96
|
+
namespace: string | null;
|
|
97
|
+
registry: Record<string, unknown>;
|
|
98
|
+
/**
|
|
99
|
+
* Initializes the class
|
|
100
|
+
* @param {String} namespace Namespace to prefix all keys with. Mostly used for the logging and reset functions
|
|
101
|
+
* @param {Object} registry (Optional) Initialize the storage provider with an existing registry
|
|
102
|
+
*/
|
|
103
|
+
protected constructor(namespace: string, registry: Record<string, unknown>);
|
|
104
|
+
/**
|
|
105
|
+
* Sets the namespace for this storage provider, and migrates
|
|
106
|
+
* all stored values to the new namespace
|
|
107
|
+
* @param {String} namespace New namespace for this storage provider
|
|
108
|
+
*/
|
|
109
|
+
abstract setNamespace(namespace: string | null): void;
|
|
110
|
+
/**
|
|
111
|
+
* Registers an item with its initial value. This is used for logging, resetting, etc.
|
|
112
|
+
* @param {String} key InternalStorage item's key
|
|
113
|
+
* @param {*} initialValue InternalStorage item's initial value
|
|
114
|
+
*/
|
|
115
|
+
register<T>(key: string, initialValue: T | null): void;
|
|
116
|
+
/**
|
|
117
|
+
* Reads an item from storage
|
|
118
|
+
* @param {String} key Key for the item to retrieve
|
|
119
|
+
*/
|
|
120
|
+
abstract getItem<T>(key: string): T | null;
|
|
121
|
+
/**
|
|
122
|
+
* Stores a value
|
|
123
|
+
* @param {String} key Item's storage key
|
|
124
|
+
* @param {String} value Item's value to store
|
|
125
|
+
*/
|
|
126
|
+
abstract setItem<T>(key: string, value: T | null): void;
|
|
127
|
+
/**
|
|
128
|
+
* Removes an item from storage
|
|
129
|
+
* @param {String} key Item's storage key
|
|
130
|
+
* @param {Boolean} fromRegistry (Optional) If the item should also be removed from the registry
|
|
131
|
+
*/
|
|
132
|
+
abstract removeItem(key: string, fromRegistry: boolean): void;
|
|
133
|
+
/**
|
|
134
|
+
* Gets all stored keys and values
|
|
135
|
+
* If a `namespace` was set, only keys prefixed with the namespace will be returned
|
|
136
|
+
*/
|
|
137
|
+
abstract getAll(): Record<string, unknown>;
|
|
138
|
+
/**
|
|
139
|
+
*
|
|
140
|
+
* @param {Boolean} useInitialValues If values should be replaced with their initial values. If false, keys are removed
|
|
141
|
+
* @param {String[]} excludedKeys (Optional) List of keys to exclude
|
|
142
|
+
* @param {Boolean} clearRegistry (Optional) If the registry should also be cleared
|
|
143
|
+
*/
|
|
144
|
+
abstract _resetAll(useInitialValues: boolean, excludedKeys: string[], clearRegistry: boolean): void;
|
|
145
|
+
/**
|
|
146
|
+
* Resets all values to their initial values
|
|
147
|
+
* If a `namespace` is set, only keys prefixed with the namespace will be reset
|
|
148
|
+
* @param {String[]} excludedKeys (Optional) List of keys to exclude
|
|
149
|
+
*/
|
|
150
|
+
abstract resetAll(excludedKeys: string[]): void;
|
|
151
|
+
/**
|
|
152
|
+
* Removes all items from local storage.
|
|
153
|
+
* If a `namespace` is set, only keys prefixed with the namespace will be removed
|
|
154
|
+
* @param {String[]} excludedKeys (Optional) List of keys to exclude
|
|
155
|
+
*/
|
|
156
|
+
abstract removeAll(excludedKeys: string[]): void;
|
|
157
|
+
upgradeToRealStorage(): boolean;
|
|
158
|
+
isUsingFakeStorage(): boolean;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* Sets the namespace for the storage provider
|
|
163
|
+
*
|
|
164
|
+
* @param {String} namespace The namespace for the storage provider
|
|
165
|
+
*/
|
|
166
|
+
export declare const setNamespace: (namespace: string) => void;
|
|
167
|
+
|
|
168
|
+
export declare const setOptions: (value: Partial<RWPOptions>) => void;
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* Attempts to upgrade the storage provider from fake storage to real localStorage
|
|
172
|
+
* This should be called on the client side after hydration
|
|
173
|
+
*
|
|
174
|
+
* @returns true if upgrade was successful
|
|
175
|
+
*/
|
|
176
|
+
export declare const upgradeStorage: () => boolean;
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* React hook that handles automatic storage upgrade after hydration
|
|
180
|
+
* This should be used in the root component of your application
|
|
181
|
+
*
|
|
182
|
+
* @param {Object} options Configuration options
|
|
183
|
+
* @param {Boolean} options.autoUpgrade Whether to automatically upgrade storage (default: true)
|
|
184
|
+
* @param {Function} options.onUpgrade Callback called when storage is upgraded
|
|
185
|
+
*/
|
|
186
|
+
export declare const useHydration: (options?: UseHydrationOptions) => {
|
|
187
|
+
hasUpgraded: boolean;
|
|
188
|
+
};
|
|
189
|
+
|
|
190
|
+
export declare type UseHydrationOptions = {
|
|
191
|
+
autoUpgrade?: boolean;
|
|
192
|
+
onUpgrade?: () => void;
|
|
193
|
+
};
|
|
194
|
+
|
|
195
|
+
export { utils }
|
|
196
|
+
|
|
197
|
+
export { }
|