valtio-define 0.4.0 → 1.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 +89 -63
- package/dist/index-3Qs1mdbd.d.mts +23 -0
- package/dist/index-BxQlAvn6.d.mts +46 -0
- package/dist/index.d.mts +13 -56
- package/dist/index.mjs +59 -132
- package/dist/persistent-CQxMybmm.mjs +32 -0
- package/dist/plugins/index.d.mts +3 -0
- package/dist/plugins/index.mjs +3 -0
- package/dist/plugins/persistent/index.d.mts +3 -0
- package/dist/plugins/persistent/index.mjs +3 -0
- package/dist/types/index.d.mts +2 -0
- package/dist/types/index.mjs +1 -0
- package/package.json +8 -1
package/README.md
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
[![npm downloads][npm-downloads-src]][npm-downloads-href]
|
|
5
5
|
[![bundle][bundle-src]][bundle-href]
|
|
6
6
|
[![JSDocs][jsdocs-src]][jsdocs-href]
|
|
7
|
+
[![coverage][coverage-src]][coverage-href]
|
|
7
8
|
[![License][license-src]][license-href]
|
|
8
9
|
|
|
9
10
|
⚡ Quickly create a fully functional and robust Valtio factory
|
|
@@ -76,49 +77,25 @@ function Counter() {
|
|
|
76
77
|
}
|
|
77
78
|
```
|
|
78
79
|
|
|
79
|
-
###
|
|
80
|
+
### Persistence
|
|
80
81
|
|
|
81
|
-
|
|
82
|
-
import { defineStore, useStatus, useStore } from 'valtio-define'
|
|
82
|
+
The persistence plugin allows you to persist store state to storage (e.g., localStorage).
|
|
83
83
|
|
|
84
|
-
|
|
85
|
-
state: () => ({ data: null }),
|
|
86
|
-
actions: {
|
|
87
|
-
async fetchData() {
|
|
88
|
-
const response = await fetch('/api/data')
|
|
89
|
-
this.data = await response.json()
|
|
90
|
-
},
|
|
91
|
-
},
|
|
92
|
-
})
|
|
84
|
+
First, register the persistent plugin:
|
|
93
85
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
86
|
+
```tsx
|
|
87
|
+
import valtio from 'valtio-define'
|
|
88
|
+
import { persistent } from 'valtio-define/plugins'
|
|
97
89
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
{status.loading && <div> Store all actions are loading...</div>}
|
|
101
|
-
{status.finished && <div> Store all actions are finished...</div>}
|
|
102
|
-
{status.error && <div> Store all actions are error...</div>}
|
|
103
|
-
|
|
104
|
-
{status.fetchData.finished && <div> Data fetched successfully...</div>}
|
|
105
|
-
{status.fetchData.error && (
|
|
106
|
-
<div>
|
|
107
|
-
{' '}
|
|
108
|
-
Error fetching data:
|
|
109
|
-
{status.fetchData.error.message}
|
|
110
|
-
</div>
|
|
111
|
-
)}
|
|
112
|
-
{state.data && <div>{JSON.stringify(state.data)}</div>}
|
|
113
|
-
<button onClick={store.fetchData}>Fetch Data</button>
|
|
114
|
-
</div>
|
|
115
|
-
)
|
|
116
|
-
}
|
|
90
|
+
// Register the persistent plugin globally
|
|
91
|
+
valtio.use(persistent())
|
|
117
92
|
```
|
|
118
93
|
|
|
119
|
-
|
|
94
|
+
Then use it in your store:
|
|
120
95
|
|
|
121
96
|
```tsx
|
|
97
|
+
import { defineStore } from 'valtio-define'
|
|
98
|
+
|
|
122
99
|
const store = defineStore({
|
|
123
100
|
state: () => ({ count: 0 }),
|
|
124
101
|
actions: {
|
|
@@ -126,11 +103,22 @@ const store = defineStore({
|
|
|
126
103
|
this.count++
|
|
127
104
|
},
|
|
128
105
|
},
|
|
129
|
-
persist:
|
|
106
|
+
persist: {
|
|
107
|
+
key: 'my-store',
|
|
108
|
+
storage: localStorage,
|
|
109
|
+
paths: ['count'], // Only persist 'count', or omit to persist all state
|
|
110
|
+
},
|
|
130
111
|
})
|
|
131
112
|
```
|
|
132
113
|
|
|
133
|
-
If
|
|
114
|
+
If `persist` is `true`, it will use `structure-id` to generate a unique key for the store automatically.
|
|
115
|
+
|
|
116
|
+
```tsx
|
|
117
|
+
const store = defineStore({
|
|
118
|
+
state: () => ({ count: 0 }),
|
|
119
|
+
persist: true, // Auto-generates key using structure-id
|
|
120
|
+
})
|
|
121
|
+
```
|
|
134
122
|
|
|
135
123
|
### Subscribe to Changes
|
|
136
124
|
|
|
@@ -149,9 +137,9 @@ const unsubscribe = store.$subscribe((state) => {
|
|
|
149
137
|
console.log('State changed:', state)
|
|
150
138
|
})
|
|
151
139
|
|
|
152
|
-
// Subscribe to
|
|
153
|
-
const
|
|
154
|
-
console.log('
|
|
140
|
+
// Subscribe to specific key changes
|
|
141
|
+
const unsubscribeKey = store.$subscribeKey('count', (value) => {
|
|
142
|
+
console.log('Count changed:', value)
|
|
155
143
|
})
|
|
156
144
|
```
|
|
157
145
|
|
|
@@ -173,15 +161,9 @@ store.$patch((state) => {
|
|
|
173
161
|
function App() {
|
|
174
162
|
return (
|
|
175
163
|
<div>
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
{state.count}
|
|
180
|
-
</div>
|
|
181
|
-
))}
|
|
182
|
-
{store.$signal.status(status => (
|
|
183
|
-
status.loading && <div>Loading...</div>
|
|
184
|
-
))}
|
|
164
|
+
Count:
|
|
165
|
+
{' '}
|
|
166
|
+
{store.$signal(state => state.count)}
|
|
185
167
|
</div>
|
|
186
168
|
)
|
|
187
169
|
}
|
|
@@ -197,7 +179,7 @@ Creates a store with state, actions, and getters.
|
|
|
197
179
|
- `store.state`: Initial state object or factory function
|
|
198
180
|
- `store.actions`: Object containing action methods
|
|
199
181
|
- `store.getters`: Object containing getter methods
|
|
200
|
-
- `store.persist`: Persistence configuration (boolean or object)
|
|
182
|
+
- `store.persist`: Persistence plugin configuration (boolean or object) - see [Persistence Plugin](#persistence-plugin)
|
|
201
183
|
|
|
202
184
|
**Returns:** Store instance with reactive state and actions
|
|
203
185
|
|
|
@@ -210,26 +192,68 @@ React hook that returns a snapshot of the store state.
|
|
|
210
192
|
|
|
211
193
|
**Returns:** Snapshot of the store state
|
|
212
194
|
|
|
213
|
-
###
|
|
195
|
+
### Plugins
|
|
214
196
|
|
|
215
|
-
|
|
197
|
+
Plugins allow you to extend store functionality. You can use plugins globally or per-store.
|
|
216
198
|
|
|
217
|
-
|
|
218
|
-
- `store`: Store instance created by `defineStore`
|
|
199
|
+
#### Global Plugin Registration
|
|
219
200
|
|
|
220
|
-
|
|
201
|
+
```tsx
|
|
202
|
+
import { use } from 'valtio-define'
|
|
203
|
+
import { persistent } from 'valtio-define/plugins'
|
|
221
204
|
|
|
222
|
-
|
|
205
|
+
// Register plugin globally - applies to all stores
|
|
206
|
+
use(persistent())
|
|
207
|
+
```
|
|
223
208
|
|
|
224
|
-
|
|
209
|
+
#### Per-Store Plugin Registration
|
|
225
210
|
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
211
|
+
```tsx
|
|
212
|
+
import { defineStore } from 'valtio-define'
|
|
213
|
+
import { persistent } from 'valtio-define/plugins'
|
|
214
|
+
|
|
215
|
+
const store = defineStore({
|
|
216
|
+
state: () => ({ count: 0 }),
|
|
217
|
+
})
|
|
218
|
+
|
|
219
|
+
// Register plugin for this specific store
|
|
220
|
+
store.use(persistent())
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
#### Creating Custom Plugins
|
|
224
|
+
|
|
225
|
+
```tsx
|
|
226
|
+
import type { Plugin } from 'valtio-define'
|
|
227
|
+
|
|
228
|
+
function myPlugin() {
|
|
229
|
+
({ store, options }: PluginContext) => {
|
|
230
|
+
// Access store methods
|
|
231
|
+
store.$subscribe((state) => {
|
|
232
|
+
console.log('State changed:', state)
|
|
233
|
+
})
|
|
234
|
+
|
|
235
|
+
// Access store options
|
|
236
|
+
if (options.someOption) {
|
|
237
|
+
// Do something
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
declare module 'valtio-define/types' {
|
|
243
|
+
export interface StoreDefine<S extends object, A extends ActionsTree, G extends Getters<any>> {
|
|
244
|
+
myPlugin?: {
|
|
245
|
+
someOption?: boolean
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
// Use the plugin
|
|
251
|
+
use(myPlugin)
|
|
252
|
+
```
|
|
231
253
|
|
|
232
|
-
**
|
|
254
|
+
**Plugin Context:**
|
|
255
|
+
- `context.store`: The store instance with all methods (`$state`, `$patch`, `$subscribe`, etc.)
|
|
256
|
+
- `context.options`: The original store definition options
|
|
233
257
|
|
|
234
258
|
## License
|
|
235
259
|
|
|
@@ -247,3 +271,5 @@ Creates a persistent proxy state.
|
|
|
247
271
|
[license-href]: https://github.com/hairyf/valtio-define/blob/main/LICENSE
|
|
248
272
|
[jsdocs-src]: https://img.shields.io/badge/jsdocs-reference-080f12?style=flat&colorA=080f12&colorB=1fa669
|
|
249
273
|
[jsdocs-href]: https://www.jsdocs.io/package/valtio-define
|
|
274
|
+
[coverage-src]: https://codecov.io/gh/hairyf/valtio-define/graph/badge.svg?token=PG5YIEEEHJ
|
|
275
|
+
[coverage-href]: https://codecov.io/gh/hairyf/valtio-define
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { s as Plugin } from "./index-BxQlAvn6.mjs";
|
|
2
|
+
import { Awaitable } from "@hairy/utils";
|
|
3
|
+
|
|
4
|
+
//#region src/plugins/persistent/index.d.ts
|
|
5
|
+
declare function persistent(): Plugin;
|
|
6
|
+
type DeepKeys<T> = T extends object ? { [K in keyof T & string]: T[K] extends object ? K | `${K}.${DeepKeys<T[K]>}` : K }[keyof T & string] : never;
|
|
7
|
+
interface Storage {
|
|
8
|
+
getItem: (key: string) => Awaitable<any>;
|
|
9
|
+
setItem: (key: string, value: any) => Awaitable<void>;
|
|
10
|
+
[key: string]: any;
|
|
11
|
+
}
|
|
12
|
+
interface PersistentOptions<S extends object = Record<string, unknown>> {
|
|
13
|
+
key?: string;
|
|
14
|
+
storage?: Storage;
|
|
15
|
+
paths?: DeepKeys<S>[];
|
|
16
|
+
}
|
|
17
|
+
declare module 'valtio-define/types' {
|
|
18
|
+
interface StoreDefine<S extends object, A extends ActionsTree, G extends Getters<any>> {
|
|
19
|
+
persist?: PersistentOptions<S>;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
//#endregion
|
|
23
|
+
export { persistent as i, PersistentOptions as n, Storage as r, DeepKeys as t };
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { ReactElement } from "react";
|
|
2
|
+
|
|
3
|
+
//#region src/types/index.d.ts
|
|
4
|
+
type Actions<S = any> = Record<string, (this: S, ...args: any) => any>;
|
|
5
|
+
type ActionsTree = Record<string, (...args: any[]) => any>;
|
|
6
|
+
type Getters<S = any> = Record<string, (this: S) => any>;
|
|
7
|
+
type ActionsOmitThisParameter<A extends Actions<any>> = { [K in keyof A]: (...args: Parameters<A[K]>) => ReturnType<A[K]> };
|
|
8
|
+
type GettersReturnType<G extends Getters<any>> = { [K in keyof G]: ReturnType<G[K]> };
|
|
9
|
+
interface StoreDefine<S extends object, A extends ActionsTree, G extends Getters<any>> {
|
|
10
|
+
state: (() => S) | S;
|
|
11
|
+
actions?: A & ThisType<A & S & GettersReturnType<G>>;
|
|
12
|
+
getters?: G & ThisType<S & GettersReturnType<G>>;
|
|
13
|
+
}
|
|
14
|
+
interface Signal<S, G extends Getters<S>> {
|
|
15
|
+
<T>(fn: (state: S & GettersReturnType<G>) => T): ReactElement;
|
|
16
|
+
}
|
|
17
|
+
type Path = (string | symbol)[];
|
|
18
|
+
type Op = [op: 'set', path: Path, value: unknown, prevValue: unknown] | [op: 'delete', path: Path, prevValue: unknown];
|
|
19
|
+
interface Subscribe<S, G extends Getters<S>> {
|
|
20
|
+
(listener: (state: S & GettersReturnType<G>, opts: Op) => void): () => void;
|
|
21
|
+
}
|
|
22
|
+
interface SubscribeKey<S, G extends Getters<S>> {
|
|
23
|
+
<T extends keyof S | keyof G>(key: T, listener: (state: (S & GettersReturnType<G>)[T]) => void): () => void;
|
|
24
|
+
}
|
|
25
|
+
interface Patch<S, G extends Getters<S>> {
|
|
26
|
+
(patch: Partial<S> | ((state: S & GettersReturnType<G>) => void)): void;
|
|
27
|
+
}
|
|
28
|
+
type Store<S, A extends Actions<S>, G extends Getters<S>> = {
|
|
29
|
+
$subscribe: Subscribe<S, G>;
|
|
30
|
+
$subscribeKey: SubscribeKey<S, G>;
|
|
31
|
+
$patch: Patch<S, G>;
|
|
32
|
+
$state: S & GettersReturnType<G> & ActionsOmitThisParameter<A>;
|
|
33
|
+
$actions: ActionsOmitThisParameter<A>;
|
|
34
|
+
$getters: GettersReturnType<G>;
|
|
35
|
+
use: (plugin: Plugin) => void;
|
|
36
|
+
$signal: Signal<S, G>;
|
|
37
|
+
} & S & GettersReturnType<G> & ActionsOmitThisParameter<A>;
|
|
38
|
+
interface PluginContext<S extends object = Record<string, unknown>> {
|
|
39
|
+
store: Store<S, Actions<S>, Getters<S>>;
|
|
40
|
+
options: StoreDefine<S, ActionsTree, Getters<S>>;
|
|
41
|
+
}
|
|
42
|
+
interface Plugin {
|
|
43
|
+
<S extends object = Record<string, unknown>>(context: PluginContext<S>): void;
|
|
44
|
+
}
|
|
45
|
+
//#endregion
|
|
46
|
+
export { GettersReturnType as a, PluginContext as c, StoreDefine as d, Subscribe as f, Getters as i, Signal as l, ActionsOmitThisParameter as n, Patch as o, SubscribeKey as p, ActionsTree as r, Plugin as s, Actions as t, Store as u };
|
package/dist/index.d.mts
CHANGED
|
@@ -1,53 +1,11 @@
|
|
|
1
|
+
import { a as GettersReturnType, d as StoreDefine, i as Getters, r as ActionsTree, s as Plugin, t as Actions, u as Store } from "./index-BxQlAvn6.mjs";
|
|
1
2
|
import { Snapshot } from "valtio";
|
|
2
3
|
|
|
3
|
-
//#region src/
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
type ActionsOmitThisParameter<A extends Actions<any>> = { [K in keyof A]: (...args: Parameters<A[K]>) => ReturnType<A[K]> };
|
|
7
|
-
interface Status {
|
|
8
|
-
finished: boolean;
|
|
9
|
-
loading: boolean;
|
|
10
|
-
error?: Error;
|
|
11
|
-
}
|
|
12
|
-
type ActionsStatus<A extends Actions<any>> = Status & { [K in keyof A]: Status };
|
|
13
|
-
type GettersReturnType<G extends Getters<any>> = { [K in keyof G]: ReturnType<G[K]> };
|
|
14
|
-
interface StoreDefine<S extends object, A extends Actions<S>, G extends Getters<S>> {
|
|
15
|
-
state: (() => S) | S;
|
|
16
|
-
actions?: A;
|
|
17
|
-
getters?: G;
|
|
18
|
-
}
|
|
19
|
-
interface StoreOptions<S extends object = Record<string, unknown>> {
|
|
20
|
-
persist?: boolean | PersistentOptions<S>;
|
|
21
|
-
}
|
|
22
|
-
interface StoreSignal<S, A extends Actions<S>, G extends Getters<S>> {
|
|
23
|
-
<T>(fn: (state: S & GettersReturnType<G>) => T): T;
|
|
24
|
-
status: <T>(fn: (status: ActionsStatus<A>) => T) => T;
|
|
25
|
-
}
|
|
26
|
-
interface StoreSubscribe<S, A extends Actions<S>, G extends Getters<S>> {
|
|
27
|
-
(listener: (state: S & GettersReturnType<G>) => void): () => void;
|
|
28
|
-
status: (listener: (status: ActionsStatus<A>) => void) => () => void;
|
|
29
|
-
key: <K$1 extends keyof S | keyof G>(key: K$1, listener: (state: (S & GettersReturnType<G>)[K$1]) => void) => () => void;
|
|
30
|
-
}
|
|
31
|
-
interface StorePatch<S, G extends Getters<S>> {
|
|
32
|
-
(patch: Partial<S> | ((state: S & GettersReturnType<G>) => void)): void;
|
|
33
|
-
}
|
|
34
|
-
type Store<S, A extends Actions<S>, G extends Getters<S>> = {
|
|
35
|
-
$subscribe: StoreSubscribe<S, A, G>;
|
|
36
|
-
$patch: StorePatch<S, G>;
|
|
37
|
-
$state: S & GettersReturnType<G> & ActionsOmitThisParameter<A>;
|
|
38
|
-
$actions: ActionsOmitThisParameter<A>;
|
|
39
|
-
$getters: GettersReturnType<G>;
|
|
40
|
-
$status: ActionsStatus<A>;
|
|
41
|
-
$signal: StoreSignal<S, A, G>;
|
|
42
|
-
} & ActionsOmitThisParameter<A>;
|
|
43
|
-
interface PersistentOptions<S extends object = Record<string, unknown>> {
|
|
44
|
-
key?: string;
|
|
45
|
-
storage?: Partial<Storage> & Pick<Storage, 'getItem' | 'setItem'>;
|
|
46
|
-
paths?: (keyof S)[];
|
|
47
|
-
initial?: (initialState: S) => any | Promise<any>;
|
|
48
|
-
}
|
|
4
|
+
//#region src/plugin.d.ts
|
|
5
|
+
declare const plugins: Plugin[];
|
|
6
|
+
declare function use(plugin: Plugin): void;
|
|
49
7
|
//#endregion
|
|
50
|
-
//#region src/define
|
|
8
|
+
//#region src/define.d.ts
|
|
51
9
|
/**
|
|
52
10
|
* @description Define a store
|
|
53
11
|
* @example
|
|
@@ -76,15 +34,14 @@ interface PersistentOptions<S extends object = Record<string, unknown>> {
|
|
|
76
34
|
*
|
|
77
35
|
* ```
|
|
78
36
|
*/
|
|
79
|
-
declare function defineStore<S extends object, A extends
|
|
37
|
+
declare function defineStore<S extends object, A extends ActionsTree, G extends Getters<S>>(define: StoreDefine<S, A, G>): Store<S, A & Actions<S>, G>;
|
|
80
38
|
//#endregion
|
|
81
|
-
//#region src/
|
|
82
|
-
declare function proxyWithPersistent<T extends object>(initialObject: T, options?: PersistentOptions): T;
|
|
83
|
-
//#endregion
|
|
84
|
-
//#region src/use-status.d.ts
|
|
85
|
-
declare function useStatus<S extends object, A extends Actions<S>, G extends Getters<S>>(store: Store<S, A, G>): Snapshot<ActionsStatus<A>>;
|
|
86
|
-
//#endregion
|
|
87
|
-
//#region src/use-store.d.ts
|
|
39
|
+
//#region src/use.d.ts
|
|
88
40
|
declare function useStore<S extends object, A extends Actions<S>, G extends Getters<S>>(store: Store<S, A, G>): Snapshot<S & GettersReturnType<G> & A>;
|
|
89
41
|
//#endregion
|
|
90
|
-
|
|
42
|
+
//#region src/index.d.ts
|
|
43
|
+
declare const _default: {
|
|
44
|
+
use: typeof use;
|
|
45
|
+
};
|
|
46
|
+
//#endregion
|
|
47
|
+
export { _default as default, defineStore, plugins, use, useStore };
|
package/dist/index.mjs
CHANGED
|
@@ -1,66 +1,15 @@
|
|
|
1
1
|
import { createElement } from "react";
|
|
2
2
|
import { proxy, ref, subscribe, useSnapshot } from "valtio";
|
|
3
3
|
import { subscribeKey } from "valtio/utils";
|
|
4
|
-
import { tryParseJson } from "@hairy/utils";
|
|
5
|
-
import { generateStructureId } from "structure-id";
|
|
6
4
|
|
|
7
|
-
//#region src/
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
loadings++ === 0 && (status.loading = true);
|
|
12
|
-
};
|
|
13
|
-
const done = () => {
|
|
14
|
-
!--loadings && (status.loading = false);
|
|
15
|
-
};
|
|
16
|
-
const fulfilled = (value) => {
|
|
17
|
-
status.finished = true;
|
|
18
|
-
if (status.error) delete status.error;
|
|
19
|
-
done();
|
|
20
|
-
return value;
|
|
21
|
-
};
|
|
22
|
-
const rejected = (error) => {
|
|
23
|
-
status.error = error;
|
|
24
|
-
done();
|
|
25
|
-
throw error;
|
|
26
|
-
};
|
|
27
|
-
return function(...args) {
|
|
28
|
-
tracking();
|
|
29
|
-
try {
|
|
30
|
-
const value = action(...args);
|
|
31
|
-
return value instanceof Promise ? value.then(fulfilled, rejected) : fulfilled(value);
|
|
32
|
-
} catch (error) {
|
|
33
|
-
rejected(error);
|
|
34
|
-
}
|
|
35
|
-
};
|
|
36
|
-
}
|
|
37
|
-
function get(obj, path) {
|
|
38
|
-
return path.split(".").reduce((result, key) => result?.[key], obj);
|
|
39
|
-
}
|
|
40
|
-
function set(obj, path, value) {
|
|
41
|
-
const keys = path.split(".");
|
|
42
|
-
const lastKey = keys.pop();
|
|
43
|
-
const target = keys.reduce((result, key) => result[key] ??= {}, obj);
|
|
44
|
-
target[lastKey] = value;
|
|
5
|
+
//#region src/plugin.ts
|
|
6
|
+
const plugins = [];
|
|
7
|
+
function use(plugin) {
|
|
8
|
+
plugins.push(plugin);
|
|
45
9
|
}
|
|
46
10
|
|
|
47
11
|
//#endregion
|
|
48
|
-
//#region src/
|
|
49
|
-
function proxyWithPersistent(initialObject, options = {}) {
|
|
50
|
-
options.key = options.key || generateStructureId(initialObject);
|
|
51
|
-
const storage = options.storage || (typeof localStorage !== "undefined" ? localStorage : void 0);
|
|
52
|
-
const state = proxy(tryParseJson(storage?.getItem(options.key)) || initialObject);
|
|
53
|
-
subscribe(state, () => {
|
|
54
|
-
const paths = options.paths || Object.keys(state);
|
|
55
|
-
const statePaths = {};
|
|
56
|
-
for (const key of paths) set(statePaths, key, get(state, key));
|
|
57
|
-
storage?.setItem(options.key, JSON.stringify(statePaths));
|
|
58
|
-
});
|
|
59
|
-
return state;
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
//#endregion
|
|
63
|
-
//#region src/define-store.ts
|
|
12
|
+
//#region src/define.ts
|
|
64
13
|
/**
|
|
65
14
|
* @description Define a store
|
|
66
15
|
* @example
|
|
@@ -89,105 +38,83 @@ function proxyWithPersistent(initialObject, options = {}) {
|
|
|
89
38
|
*
|
|
90
39
|
* ```
|
|
91
40
|
*/
|
|
92
|
-
function defineStore(
|
|
93
|
-
const state = typeof
|
|
94
|
-
const getters =
|
|
95
|
-
const actions =
|
|
96
|
-
const
|
|
97
|
-
status.finished = false;
|
|
98
|
-
status.loading = false;
|
|
99
|
-
status.error = void 0;
|
|
100
|
-
const $status = proxy(status);
|
|
101
|
-
const $state = store.persist ? proxyWithPersistent(state, store.persist === true ? {} : store.persist) : proxy(state);
|
|
41
|
+
function defineStore(define) {
|
|
42
|
+
const state = typeof define.state === "function" ? define.state() : define.state;
|
|
43
|
+
const getters = define.getters || {};
|
|
44
|
+
const actions = define.actions || {};
|
|
45
|
+
const $state = proxy(state);
|
|
102
46
|
const $actions = {};
|
|
103
47
|
const $getters = {};
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
48
|
+
const $plugins = [];
|
|
49
|
+
for (const key in actions) {
|
|
50
|
+
$actions[key] = ref(actions[key].bind($state));
|
|
51
|
+
$state[key] = $actions[key];
|
|
52
|
+
}
|
|
53
|
+
for (const key in getters) {
|
|
54
|
+
Object.defineProperty($state, key, {
|
|
55
|
+
get: () => getters[key].call($state),
|
|
56
|
+
enumerable: true
|
|
57
|
+
});
|
|
58
|
+
Object.defineProperty($getters, key, {
|
|
59
|
+
get: () => $state[key],
|
|
60
|
+
enumerable: true
|
|
61
|
+
});
|
|
62
|
+
}
|
|
107
63
|
function $subscribe(listener) {
|
|
108
|
-
return subscribe($state, () => listener($state));
|
|
64
|
+
return subscribe($state, (opts) => listener($state, opts));
|
|
65
|
+
}
|
|
66
|
+
function $subscribeKey(key, listener) {
|
|
67
|
+
return subscribeKey($state, key, (value) => listener(value), true);
|
|
109
68
|
}
|
|
110
|
-
$subscribe.status = function(listener) {
|
|
111
|
-
return subscribe($status, () => listener($status));
|
|
112
|
-
};
|
|
113
|
-
$subscribe.key = function(key, listener) {
|
|
114
|
-
return subscribeKey($state, key, () => listener($state));
|
|
115
|
-
};
|
|
116
69
|
function $patch(patch) {
|
|
117
|
-
|
|
118
|
-
else Object.assign($state, patch);
|
|
70
|
+
typeof patch === "function" ? patch($state) : Object.assign($state, patch);
|
|
119
71
|
}
|
|
120
72
|
function $signal(fn) {
|
|
121
73
|
return createElement(() => fn(useSnapshot($state)));
|
|
122
74
|
}
|
|
123
|
-
$
|
|
124
|
-
|
|
125
|
-
}
|
|
126
|
-
|
|
75
|
+
function use$1(plugin) {
|
|
76
|
+
plugins.push(plugin);
|
|
77
|
+
}
|
|
78
|
+
const base = {
|
|
127
79
|
$subscribe,
|
|
80
|
+
$subscribeKey,
|
|
128
81
|
$patch,
|
|
129
82
|
$state,
|
|
130
|
-
$status,
|
|
131
83
|
$actions,
|
|
132
84
|
$getters,
|
|
133
85
|
$signal,
|
|
134
|
-
|
|
86
|
+
use: use$1
|
|
135
87
|
};
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
$actions[key] = track(actions[key].bind($state), $status[key]);
|
|
145
|
-
Object.defineProperty($state, key, {
|
|
146
|
-
get: () => ref($actions[key]),
|
|
147
|
-
enumerable: false
|
|
148
|
-
});
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
function setupGetters($state, getters, $getters) {
|
|
152
|
-
for (const key in getters) {
|
|
153
|
-
Object.defineProperty($getters, key, {
|
|
154
|
-
get: () => $state[key],
|
|
155
|
-
enumerable: true
|
|
156
|
-
});
|
|
157
|
-
Object.defineProperty($state, key, {
|
|
158
|
-
get: () => getters[key].call($state),
|
|
159
|
-
enumerable: true
|
|
160
|
-
});
|
|
161
|
-
}
|
|
162
|
-
}
|
|
163
|
-
function setupStatus($actions, $status) {
|
|
164
|
-
Object.defineProperty($status, "loading", {
|
|
165
|
-
get: () => Object.keys($actions).some((key) => $status[key].loading),
|
|
166
|
-
enumerable: true
|
|
167
|
-
});
|
|
168
|
-
Object.defineProperty($status, "finished", {
|
|
169
|
-
get: () => Object.keys($actions).every((key) => $status[key].finished),
|
|
170
|
-
enumerable: true
|
|
171
|
-
});
|
|
172
|
-
Object.defineProperty($status, "error", {
|
|
173
|
-
get: () => {
|
|
174
|
-
return $status[Object.keys($actions).find((key) => $status[key].error) || ""]?.error;
|
|
88
|
+
const store = new Proxy(base, {
|
|
89
|
+
get(target, prop) {
|
|
90
|
+
if (prop in $actions) return $actions[prop];
|
|
91
|
+
if (prop in target) return target[prop];
|
|
92
|
+
return $state[prop];
|
|
93
|
+
},
|
|
94
|
+
has(target, prop) {
|
|
95
|
+
return prop in target || prop in $actions || prop in $state;
|
|
175
96
|
},
|
|
176
|
-
|
|
97
|
+
set(target, prop, value) {
|
|
98
|
+
prop in $state ? $state[prop] = value : target[prop] = value;
|
|
99
|
+
return true;
|
|
100
|
+
}
|
|
177
101
|
});
|
|
102
|
+
for (const plugin of [...plugins, ...$plugins]) plugin({
|
|
103
|
+
store,
|
|
104
|
+
options: define
|
|
105
|
+
});
|
|
106
|
+
return store;
|
|
178
107
|
}
|
|
179
108
|
|
|
180
109
|
//#endregion
|
|
181
|
-
//#region src/use
|
|
182
|
-
function useStatus(store) {
|
|
183
|
-
return useSnapshot(store.$status);
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
//#endregion
|
|
187
|
-
//#region src/use-store.ts
|
|
110
|
+
//#region src/use.ts
|
|
188
111
|
function useStore(store) {
|
|
189
112
|
return useSnapshot(store.$state);
|
|
190
113
|
}
|
|
191
114
|
|
|
192
115
|
//#endregion
|
|
193
|
-
|
|
116
|
+
//#region src/index.ts
|
|
117
|
+
var src_default = { use };
|
|
118
|
+
|
|
119
|
+
//#endregion
|
|
120
|
+
export { src_default as default, defineStore, plugins, use, useStore };
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { subscribe } from "valtio";
|
|
2
|
+
import { get, set } from "@hairy/utils";
|
|
3
|
+
import { destr } from "destr";
|
|
4
|
+
import { generateStructureId } from "structure-id";
|
|
5
|
+
|
|
6
|
+
//#region src/plugins/persistent/index.ts
|
|
7
|
+
function persistent() {
|
|
8
|
+
return (context) => {
|
|
9
|
+
const options = context.options.persist || {};
|
|
10
|
+
options.key = options.key || generateStructureId(context.store.$state);
|
|
11
|
+
const storage = options.storage || (typeof localStorage !== "undefined" ? localStorage : void 0);
|
|
12
|
+
const value = storage?.getItem(options.key);
|
|
13
|
+
let __watch = false;
|
|
14
|
+
if (value instanceof Promise) value.then(initialize);
|
|
15
|
+
else initialize(value);
|
|
16
|
+
function initialize(value$1) {
|
|
17
|
+
Object.assign(context.store.$state, destr(value$1));
|
|
18
|
+
__watch = true;
|
|
19
|
+
}
|
|
20
|
+
subscribe(context.store.$state, () => {
|
|
21
|
+
if (!__watch) return;
|
|
22
|
+
const paths = options.paths || Object.keys(context.store.$state);
|
|
23
|
+
const statePaths = {};
|
|
24
|
+
for (const key of paths) set(statePaths, key, get(context.store.$state, key));
|
|
25
|
+
const value$1 = JSON.stringify(statePaths);
|
|
26
|
+
storage?.setItem(options.key, value$1);
|
|
27
|
+
});
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
//#endregion
|
|
32
|
+
export { persistent as t };
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import { a as GettersReturnType, c as PluginContext, d as StoreDefine, f as Subscribe, i as Getters, l as Signal, n as ActionsOmitThisParameter, o as Patch, p as SubscribeKey, r as ActionsTree, s as Plugin, t as Actions, u as Store } from "../index-BxQlAvn6.mjs";
|
|
2
|
+
export { Actions, ActionsOmitThisParameter, ActionsTree, Getters, GettersReturnType, Patch, Plugin, PluginContext, Signal, Store, StoreDefine, Subscribe, SubscribeKey };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { };
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "valtio-define",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "1.0.0",
|
|
5
5
|
"description": "⚡quickly create a fully functional and robust Valtio factory",
|
|
6
6
|
"author": "Hairyf <wwu710632@gmail.com>",
|
|
7
7
|
"license": "MIT",
|
|
@@ -14,6 +14,9 @@
|
|
|
14
14
|
"keywords": [],
|
|
15
15
|
"sideEffects": false,
|
|
16
16
|
"publishConfig": {
|
|
17
|
+
"./plugins": "./dist/plugins/index.mjs",
|
|
18
|
+
"./plugins/persistent": "./dist/plugins/persistent/index.mjs",
|
|
19
|
+
"./types": "./dist/types/index.mjs",
|
|
17
20
|
"access": "public"
|
|
18
21
|
},
|
|
19
22
|
"exports": {
|
|
@@ -30,6 +33,7 @@
|
|
|
30
33
|
},
|
|
31
34
|
"dependencies": {
|
|
32
35
|
"@hairy/utils": "^1.46.0",
|
|
36
|
+
"destr": "^2.0.5",
|
|
33
37
|
"structure-id": "^1.2.9",
|
|
34
38
|
"valtio": "^2.2.0"
|
|
35
39
|
},
|
|
@@ -39,6 +43,7 @@
|
|
|
39
43
|
"@antfu/utils": "^9.3.0",
|
|
40
44
|
"@types/node": "^24.10.0",
|
|
41
45
|
"@types/react": "^19.2.6",
|
|
46
|
+
"@types/react-dom": "^19.2.3",
|
|
42
47
|
"@vitejs/plugin-react": "^5.1.1",
|
|
43
48
|
"@vitest/browser-playwright": "^4.0.15",
|
|
44
49
|
"@vitest/coverage-v8": "^4.0.15",
|
|
@@ -47,6 +52,7 @@
|
|
|
47
52
|
"lint-staged": "^16.2.6",
|
|
48
53
|
"playwright": "^1.57.0",
|
|
49
54
|
"react": "^19.2.0",
|
|
55
|
+
"react-dom": "^19.2.0",
|
|
50
56
|
"simple-git-hooks": "^2.13.1",
|
|
51
57
|
"tinyexec": "^1.0.2",
|
|
52
58
|
"tsdown": "^0.16.0",
|
|
@@ -72,6 +78,7 @@
|
|
|
72
78
|
"release": "bumpp",
|
|
73
79
|
"start": "tsx src/index.ts",
|
|
74
80
|
"test": "vitest",
|
|
81
|
+
"coverage": "vitest run --coverage",
|
|
75
82
|
"typecheck": "tsc"
|
|
76
83
|
}
|
|
77
84
|
}
|