valtio-define 1.1.5 → 1.2.1

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 CHANGED
@@ -1,25 +1,35 @@
1
- # valtio-define
1
+ ![image](./logo.svg)
2
2
 
3
3
  [![npm version][npm-version-src]][npm-version-href]
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
7
  [![coverage][coverage-src]][coverage-href]
8
- [![License][license-src]][license-href]
8
+ [![License][license-src]][license-href].
9
9
 
10
- Quickly create a fully functional and robust [Valtio](https://valtio.dev) factory
10
+ ⚡️ **valtio-define** is a lightweight factory for creating fully functional, robust [Valtio](https://github.com/pmndrs/valtio) stores. It simplifies state management in React by providing a structured API for state, actions, and computed getters.
11
11
 
12
- ## Installation
12
+ ## 📦 Installation
13
13
 
14
14
  ```bash
15
15
  pnpm add valtio-define
16
16
  ```
17
17
 
18
- ## Usage
18
+ <details>
19
+ <summary>Are you an AI?</summary>
20
+
21
+ You can run <code>npx skills add hairyf/valtio-define --skill valtio-define -y</code> to install the skills!
22
+
23
+ Remember to ask your owner which <a href="https://github.com/vercel-labs/skills?tab=readme-ov-file#supported-agents">Agents</a> need to be supported (using the <code>--agent</code> parameter of skills) to avoid installing too many default <code>agents</code> directories.
24
+
25
+ </details>
26
+
27
+ ## 🚀 Quick Start
28
+
19
29
 
20
30
  ### Basic Store
21
31
 
22
- Create a reactive store with state and actions. The store provides a simple and intuitive API for managing state in React applications, built on top of Valtio.
32
+ `defineStore` allows you to encapsulate state and logic in one place. Use `useStore` to consume the reactive state in your components.
23
33
 
24
34
  ```tsx
25
35
  import { defineStore, useStore } from 'valtio-define'
@@ -28,6 +38,7 @@ const store = defineStore({
28
38
  state: () => ({ count: 0 }),
29
39
  actions: {
30
40
  increment() {
41
+ // 'this' refers to the reactive state
31
42
  this.count++
32
43
  },
33
44
  },
@@ -35,18 +46,22 @@ const store = defineStore({
35
46
 
36
47
  function Counter() {
37
48
  const { count } = useStore(store)
49
+
38
50
  return (
39
51
  <div>
52
+ <div>
53
+ Count:
54
+ {count}
55
+ </div>
40
56
  <button onClick={store.increment}>Increment</button>
41
- <div>{count}</div>
42
57
  </div>
43
58
  )
44
59
  }
45
60
  ```
46
61
 
47
- ### With Getters
62
+ ### Derived State (Getters)
48
63
 
49
- Getters are computed properties that automatically update when their dependencies change. They provide a clean way to derive state without manually tracking dependencies.
64
+ Getters are **computed properties**. They automatically re-evaluate when their dependencies change, providing a clean way to derive data.
50
65
 
51
66
  ```tsx
52
67
  const store = defineStore({
@@ -62,314 +77,175 @@ const store = defineStore({
62
77
  },
63
78
  },
64
79
  })
65
-
66
- function Counter() {
67
- const state = useStore(store)
68
- return (
69
- <div>
70
- <div>
71
- Count:
72
- {state.count}
73
- </div>
74
- <div>
75
- Doubled:
76
- {state.doubled}
77
- </div>
78
- <button onClick={store.increment}>Increment</button>
79
- </div>
80
- )
81
- }
82
80
  ```
83
81
 
84
- ### Persistence
85
-
86
- The persistence plugin allows you to persist store state to storage (e.g., localStorage).
87
-
88
- First, register the persist plugin:
82
+ -----
89
83
 
90
- ```tsx
91
- import valtio from 'valtio-define'
92
- import { persist } from 'valtio-define/plugins'
84
+ ## 🛠 Advanced Features
93
85
 
94
- // Register the persist plugin globally
95
- valtio.use(persist())
96
- ```
86
+ ### The Power of `this`
97
87
 
98
- Then use it in your store:
88
+ Inside `actions` and `getters`, `this` provides full access to the store's state, other actions, and other getters. This type safety across the entire store.
99
89
 
100
90
  ```tsx
101
- import { defineStore } from 'valtio-define'
102
-
103
91
  const store = defineStore({
104
- state: () => ({ count: 0 }),
92
+ state: () => ({
93
+ count: 0,
94
+ }),
105
95
  actions: {
106
- increment() {
107
- this.count++
96
+ // Autocompletion and typings for the whole store ✨
97
+ currentDoubledOne() {
98
+ return this.doublePlusOne
108
99
  },
109
100
  },
110
- persist: {
111
- key: 'my-store',
112
- storage: localStorage,
113
- paths: ['count'], // Only persist 'count', or omit to persist all state
101
+ getters: {
102
+ doubled() {
103
+ return this.count * 2
104
+ },
105
+ // Note: The return type **must** be explicitly set for complex getters
106
+ doublePlusOne() {
107
+ // Access other getters via 'this'
108
+ return this.doubled + 1
109
+ },
114
110
  },
115
111
  })
116
112
  ```
117
113
 
118
- If `persist` is `true`, it will use `structure-id` to generate a unique key for the store automatically.
114
+ ### Persistence
119
115
 
120
- ```tsx
121
- const store = defineStore({
122
- state: () => ({ count: 0 }),
123
- persist: true, // Auto-generates key using structure-id
124
- })
125
- ```
116
+ Save and restore your store state using the `persist` plugin.
126
117
 
127
- You can pass `hydrate` when registering the plugin (default `true`). When `true`, state is hydrated from storage as soon as the store is created. Set `hydrate: false` when you need to avoid running persistence during server-side rendering, and manually mount persist in your App entry instead:
118
+ 1. **Global Registration:**
128
119
 
129
- ```tsx
130
- // Register with hydrate: false
131
- store.use(persist({ hydrate: false }))
120
+ ```tsx
121
+ import valtio from 'valtio-define'
122
+ import { persist } from 'valtio-define/plugins'
132
123
 
133
- // In your App (client entry), after store is used:
134
- useEffect(() => store.$persist.mount(), [])
135
- ```
124
+ valtio.use(persist())
125
+ ```
136
126
 
137
- ### Subscribe to Changes
127
+ 2. **Store Configuration:**
138
128
 
139
- ```tsx
140
- const store = defineStore({
141
- state: () => ({ count: 0 }),
142
- actions: {
143
- increment() {
144
- this.count++
145
- },
146
- },
147
- })
129
+ ```tsx
130
+ const store = defineStore({
131
+ state: () => ({ count: 0 }),
132
+ persist: {
133
+ key: 'my-app-storage',
134
+ storage: localStorage,
135
+ paths: ['count'], // Optional: Persist specific keys only
136
+ },
137
+ })
138
+ ```
148
139
 
149
- // Subscribe to state changes
150
- const unsubscribe = store.$subscribe((state) => {
151
- console.log('State changed:', state)
152
- })
140
+ > **Tip:** If you set `persist: true`, a unique key is automatically generated using `structure-id`.
153
141
 
154
- // Subscribe to specific key changes
155
- const unsubscribeKey = store.$subscribeKey('count', (value) => {
156
- console.log('Count changed:', value)
157
- })
158
- ```
142
+ ### Manual Hydration (SSR Friendly)
159
143
 
160
- ### Patch State
144
+ To avoid hydration mismatches during Server-Side Rendering, disable automatic hydration and mount it in a `useEffect`.
161
145
 
162
146
  ```tsx
163
- // Patch with object
164
- store.$patch({ count: 10 })
147
+ // Register with hydrate disabled
148
+ store.use(persist({ hydrate: false }))
165
149
 
166
- // Patch with function
167
- store.$patch((state) => {
168
- state.count += 5
169
- })
150
+ // In your Client Entry / App Root
151
+ useEffect(() => {
152
+ store.$persist.mount()
153
+ }, [])
170
154
  ```
171
155
 
172
- ### Signal (JSX Component)
156
+ ### React-Idiomatic State Hooks
173
157
 
174
- ```tsx
175
- function App() {
176
- return (
177
- <div>
178
- Count:
179
- {' '}
180
- {store.$signal(state => state.count)}
181
- </div>
182
- )
183
- }
184
- ```
185
-
186
- ### Store to State Hooks
187
-
188
- Convert store state to React hooks similar to `useState`. This provides a more React-idiomatic way to access and update store state.
189
-
190
- #### `storeToState(store, key)`
191
-
192
- Returns a tuple `[state, setter]` for a single store key, similar to React's `useState`.
158
+ If you prefer the `useState` syntax, use `storeToState` or `storeToStates`. These return `[state, setter]` tuples.
193
159
 
194
160
  ```tsx
195
- import { defineStore, storeToState } from 'valtio-define'
196
-
197
- const store = defineStore({
198
- state: { count: 0, name: 'test' },
199
- })
200
-
201
- function Counter() {
202
- const [count, setCount] = storeToState(store, 'count')
161
+ function Profile() {
162
+ // Access a single key
203
163
  const [name, setName] = storeToState(store, 'name')
204
164
 
205
- return (
206
- <div>
207
- <button onClick={() => setCount(count + 1)}>Increment</button>
208
- <button onClick={() => setCount(prev => prev + 1)}>Increment (functional)</button>
209
- <div>
210
- Count:
211
- {count}
212
- </div>
213
- <div>
214
- Name:
215
- {name}
216
- </div>
217
- </div>
218
- )
165
+ // Access all keys as hooks
166
+ const {
167
+ count: [count, setCount]
168
+ } = storeToStates(store)
169
+
170
+ return <input value={name} onChange={e => setName(e.target.value)} />
219
171
  }
220
172
  ```
221
173
 
222
- **Parameters:**
223
- - `store`: Store instance created by `defineStore`
224
- - `key`: Key of the state property to access
174
+ ### Controlled inputs may lose caret position
225
175
 
226
- **Returns:** `[state, setter]` tuple where:
227
- - `state`: Current value of the state property
228
- - `setter`: Function to update the state (accepts value or updater function)
176
+ Ref: https://github.com/pmndrs/valtio/issues/270
229
177
 
230
- #### `storeToStates(store)`
178
+ This happens because Valtio batches state updates causing React to re-render after the input event. React resets the DOM value and loses the caret position.
231
179
 
232
- Returns an object with all store keys mapped to `[state, setter]` tuples.
180
+ Use `{ sync: true }` to update synchronously and preserve the caret:
233
181
 
234
182
  ```tsx
235
- function Component() {
236
- const {
237
- count: [count, setCount],
238
- name: [name, setName],
239
- user: [user, setUser],
240
- } = storeToStates(store)
183
+ function Input() {
184
+ const { text } = useStore(store, { sync: true })
185
+ // const [text, setText] = storeToState(store, 'text', { sync: true })
241
186
 
242
187
  return (
243
- <div>
244
- <button onClick={() => setCount(count + 1)}>Increment</button>
245
- <div>
246
- Count:
247
- {count}
248
- </div>
249
- <div>
250
- Name:
251
- {name}
252
- </div>
253
- <div>
254
- User:
255
- {user.name}
256
- </div>
257
- </div>
188
+ <input
189
+ onChange={e => store.text = e.target.value}
190
+ value={text}
191
+ />
258
192
  )
259
193
  }
260
194
  ```
261
195
 
262
- **Parameters:**
263
- - `store`: Store instance created by `defineStore`
264
-
265
- **Returns:** Object where each key maps to a `[state, setter]` tuple
266
-
267
- ## API
268
-
269
- ### `defineStore(store)`
270
-
271
- Creates a store with state, actions, and getters.
272
-
273
- **Parameters:**
274
- - `store.state`: Initial state object or factory function
275
- - `store.actions`: Object containing action methods
276
- - `store.getters`: Object containing getter methods
277
- - `store.persist`: Persistence plugin configuration (boolean or object) - see [Persistence Plugin](#persistence)
278
-
279
- **Returns:** Store instance with reactive state and actions
280
-
281
- ### `useStore(store)`
282
-
283
- React hook that returns a snapshot of the store state.
284
-
285
- **Parameters:**
286
- - `store`: Store instance created by `defineStore`
287
-
288
- **Returns:** Snapshot of the store state
196
+ -----
289
197
 
290
- ### `storeToState(store, key)`
198
+ ## 🛰 Store API
291
199
 
292
- React hook that returns a `[state, setter]` tuple for a single store key, similar to React's `useState`.
200
+ Every store instance created with `defineStore` includes built-in utility methods:
293
201
 
294
- **Parameters:**
295
- - `store`: Store instance created by `defineStore`
296
- - `key`: Key of the state property to access
202
+ * **`$patch(obj | fn)`**: Bulk update the state.
203
+ * **`$subscribe(callback)`**: Watch the entire store for changes.
204
+ * **`$subscribeKey(key, callback)`**: Watch a specific property.
205
+ * **`$signal(selector)`**: Use a selector function inside JSX for fine-grained reactivity.
297
206
 
298
- **Returns:** `[state, setter]` tuple where:
299
- - `state`: Current value of the state property
300
- - `setter`: Function to update the state (accepts value or updater function like `setState(value)` or `setState(prev => newValue)`)
207
+ -----
301
208
 
302
- ### `storeToStates(store)`
209
+ ## 🔌 Plugins
303
210
 
304
- React hook that returns an object with all store keys mapped to `[state, setter]` tuples.
211
+ ### Global vs. Per-Store
305
212
 
306
- **Parameters:**
307
- - `store`: Store instance created by `defineStore`
308
-
309
- **Returns:** Object where each key maps to a `[state, setter]` tuple, preserving the correct type for each property
310
-
311
- ### Plugins
312
-
313
- Plugins allow you to extend store functionality. You can use plugins globally or per-store.
314
-
315
- #### Global Plugin Registration
213
+ Plugins can be applied to all stores or restricted to a single instance.
316
214
 
317
215
  ```tsx
318
- import valtio from 'valtio-define'
319
- import { persist } from 'valtio-define/plugins'
216
+ // Global
217
+ valtio.use(myPlugin())
320
218
 
321
- // Register plugin globally - applies to all stores
322
- valtio.use(persist())
219
+ // Local
220
+ const store = defineStore({ /* ... */ })
221
+ store.use(myPlugin())
323
222
  ```
324
223
 
325
- #### Per-Store Plugin Registration
224
+ ### Creating a Custom Plugin
326
225
 
327
- ```tsx
328
- import { defineStore } from 'valtio-define'
329
- import { persist } from 'valtio-define/plugins'
330
-
331
- const store = defineStore({
332
- state: () => ({ count: 0 }),
333
- })
334
-
335
- // Register plugin for this specific store
336
- store.use(persist())
337
- ```
338
-
339
- #### Creating Custom Plugins
226
+ Extend functionality by accessing the `store` instance and `options` through the plugin context.
340
227
 
341
228
  ```tsx
342
229
  import type { Plugin } from 'valtio-define'
343
230
 
344
- function myPlugin() {
345
- ({ store, options }: PluginContext) => {
346
- // Access store methods
231
+ function loggerPlugin(): Plugin {
232
+ return ({ store, options }) => {
347
233
  store.$subscribe((state) => {
348
- console.log('State changed:', state)
234
+ console.log('Update:', state)
349
235
  })
350
-
351
- // Access store options
352
- if (options.someOption) {
353
- // Do something
354
- }
355
236
  }
356
237
  }
357
238
 
358
239
  declare module 'valtio-define' {
359
- export interface StoreDefine<S extends object, A extends ActionsTree, G extends Getters<any>> {
360
- myPlugin?: {
240
+ export interface StoreDefineOptions<S extends object> {
241
+ $myPlugin?: {
361
242
  someOption?: boolean
362
243
  }
363
244
  }
364
245
  }
365
-
366
- // Use the plugin
367
- use(myPlugin())
368
246
  ```
369
247
 
370
- **Plugin Context:**
371
- - `context.store`: The store instance with all methods (`$state`, `$patch`, `$subscribe`, etc.)
372
- - `context.options`: The original store definition options
248
+ -----
373
249
 
374
250
  ## License
375
251
 
package/dist/index.d.mts CHANGED
@@ -1,4 +1,4 @@
1
- import { a as GettersReturnType, c as PluginContext, d as StoreDefine, f as StoreDefineOptions, h as SubscribeKey, i as Getters, l as Signal, m as Subscribe, n as ActionsOmitThisParameter, o as Patch, p as StoreOptions, r as ActionsTree, s as Plugin, t as Actions, u as Store } from "./types-BW_uQuTb.mjs";
1
+ import { a as GettersReturnType, c as PluginContext, d as StoreDefine, f as StoreDefineOptions, h as SubscribeKey, i as Getters, l as Signal, m as Subscribe, n as ActionsOmitThisParameter, o as Patch, p as StoreOptions, r as ActionsTree, s as Plugin, t as Actions, u as Store } from "./types-CqDu3QIJ.mjs";
2
2
  import { Snapshot } from "valtio";
3
3
  import { Dispatch, SetStateAction } from "react";
4
4
 
@@ -38,18 +38,21 @@ declare function use(plugin: Plugin): void;
38
38
  declare function defineStore<S extends object = {}, A extends Actions<S> = {}, G extends Getters<S> = {}>(define: StoreDefine<S, A, G>): Store<S, A, G>;
39
39
  //#endregion
40
40
  //#region src/hooks.d.ts
41
- interface UseStoreOptions {
41
+ declare function useStore<S extends object, A extends Actions<S>, G extends Getters<S>>(store: Store<S, A, G>, options?: {
42
42
  sync?: boolean;
43
- }
44
- declare function useStore<S extends object, A extends Actions<S>, G extends Getters<S>>(store: Store<S, A, G>, options?: UseStoreOptions): Snapshot<S & GettersReturnType<G> & A>;
43
+ }): Snapshot<S & GettersReturnType<G> & A>;
45
44
  //#endregion
46
45
  //#region src/utils.d.ts
47
- declare function storeToState<S extends object, K extends keyof S>(store: Store<S>, key: K): [S[K], Dispatch<SetStateAction<S[K]>>];
48
- declare function storeToStates<S extends object>(store: Store<S>): { [K in keyof S]: [S[K], Dispatch<SetStateAction<S[K]>>] };
46
+ declare function storeToState<S extends object, K extends keyof S>(store: Store<S>, key: K, options?: {
47
+ sync?: boolean;
48
+ }): [S[K], Dispatch<SetStateAction<S[K]>>];
49
+ declare function storeToStates<S extends object>(store: Store<S>, options?: {
50
+ sync?: boolean;
51
+ }): { [K in keyof S]: [S[K], Dispatch<SetStateAction<S[K]>>] };
49
52
  //#endregion
50
53
  //#region src/index.d.ts
51
54
  declare const _default: {
52
55
  use: typeof use;
53
56
  };
54
57
  //#endregion
55
- export { Actions, ActionsOmitThisParameter, ActionsTree, Getters, GettersReturnType, Patch, Plugin, PluginContext, Signal, Store, StoreDefine, StoreDefineOptions, StoreOptions, Subscribe, SubscribeKey, UseStoreOptions, _default as default, defineStore, plugins, storeToState, storeToStates, use, useStore };
58
+ export { Actions, ActionsOmitThisParameter, ActionsTree, Getters, GettersReturnType, Patch, Plugin, PluginContext, Signal, Store, StoreDefine, StoreDefineOptions, StoreOptions, Subscribe, SubscribeKey, _default as default, defineStore, plugins, storeToState, storeToStates, use, useStore };
package/dist/index.mjs CHANGED
@@ -1 +1 @@
1
- import{proxy as e,ref as t,subscribe as n,useSnapshot as r}from"valtio";import{createElement as i}from"react";import{subscribeKey as a}from"valtio/utils";const o=e([]);function s(e){o.push(e)}function c(s){let c=typeof s.state==`function`?s.state():s.state,u=s.getters||{},d=s.actions||{},f=e(c),p={},m={},h=new WeakSet;for(let e in d)p[e]=t(d[e].bind(f)),f[e]=p[e];for(let e in u)l(f,e,()=>u[e].call(f)),l(m,e,()=>f[e]);function g(e){return n(f,t=>e(f,t))}function _(e,t){return a(f,e,e=>t(e),!0)}function v(e){typeof e==`function`?e(f):Object.assign(f,e)}function y(e){return i(()=>e(r(f)))}function b(e){o.push(e),C(e)}let x={$subscribe:g,$subscribeKey:_,$patch:v,$state:f,$actions:p,$getters:m,$signal:y,use:b},S=new Proxy(x,{get(e,t){return t in p?p[t]:t in e?e[t]:f[t]},has(e,t){return t in e||t in p||t in f},set(e,t,n){return t in f?f[t]=n:e[t]=n,!0}});function C(e){h.has(e)||(h.add(e),e({store:S,options:s}))}for(let e of o)C(e);return n(o,()=>{for(let e of o)C(e)}),S}function l(e,t,n){Object.defineProperty(e,t,{get:n,enumerable:!0})}function u(e,t){return r(e.$state,t)}function d(e,t){let n=u(e);function r(n){typeof n==`function`?e.$patch(e=>{e[t]=n(e[t])}):e.$patch(e=>{e[t]=n})}return[n[t],r]}function f(e){return Object.fromEntries(Object.keys(e.$state).map(t=>[t,d(e,t)]))}var p={use:s};export{p as default,c as defineStore,o as plugins,d as storeToState,f as storeToStates,s as use,u as useStore};
1
+ import{proxy as e,ref as t,subscribe as n,useSnapshot as r}from"valtio";import{createElement as i}from"react";import{subscribeKey as a}from"valtio/utils";const o=e([]);function s(e){o.push(e)}function c(s){let c=typeof s.state==`function`?s.state():s.state,u=s.getters||{},d=s.actions||{},f=e(c),p={},m={},h=new WeakSet;for(let e in d)p[e]=t(d[e].bind(f)),f[e]=p[e];for(let e in u)l(f,e,()=>u[e].call(f)),l(m,e,()=>f[e]);function g(e){return n(f,t=>e(f,t))}function _(e,t){return a(f,e,e=>t(e),!0)}function v(e){typeof e==`function`?e(f):Object.assign(f,e)}function y(e){return i(()=>e(r(f)))}function b(e){o.push(e),C(e)}let x={$subscribe:g,$subscribeKey:_,$patch:v,$state:f,$actions:p,$getters:m,$signal:y,use:b},S=new Proxy(x,{get(e,t){return t in p?p[t]:t in e?e[t]:f[t]},has(e,t){return t in e||t in p||t in f},set(e,t,n){return t in f?f[t]=n:e[t]=n,!0}});function C(e){h.has(e)||(h.add(e),e({store:S,options:s}))}for(let e of o)C(e);return n(o,()=>{for(let e of o)C(e)}),S}function l(e,t,n){Object.defineProperty(e,t,{get:n,enumerable:!0})}function u(e,t){return r(e.$state,t)}function d(e,t,n){let r=u(e,n);function i(n){typeof n==`function`?e.$patch(e=>{e[t]=n(e[t])}):e.$patch(e=>{e[t]=n})}return[r[t],i]}function f(e,t){return Object.fromEntries(Object.keys(e.$state).map(n=>[n,d(e,n,t)]))}var p={use:s};export{p as default,c as defineStore,o as plugins,d as storeToState,f as storeToStates,s as use,u as useStore};
@@ -1,2 +1,2 @@
1
- import { PersistentMountOptions, StorePersistentOptions, persist } from "./persist/index.mjs";
2
- export { PersistentMountOptions, StorePersistentOptions, persist };
1
+ import { PersistentMountOptions, persist } from "./persist/index.mjs";
2
+ export { PersistentMountOptions, persist };
@@ -1,4 +1,4 @@
1
- import { s as Plugin } from "../../types-BW_uQuTb.mjs";
1
+ import { s as Plugin } from "../../types-CqDu3QIJ.mjs";
2
2
  import { PersistentOptions, PersistentStore } from "./types.mjs";
3
3
 
4
4
  //#region src/plugins/persist/index.d.ts
@@ -8,9 +8,6 @@ interface PersistentMountOptions {
8
8
  */
9
9
  hydrate?: boolean;
10
10
  }
11
- interface StorePersistentOptions {
12
- mount: () => void;
13
- }
14
11
  declare function persist({
15
12
  hydrate
16
13
  }?: PersistentMountOptions): Plugin;
@@ -21,4 +18,4 @@ declare module 'valtio-define' {
21
18
  interface StoreOptions extends PersistentStore {}
22
19
  }
23
20
  //#endregion
24
- export { PersistentMountOptions, StorePersistentOptions, persist };
21
+ export { PersistentMountOptions, persist };
@@ -1 +1 @@
1
- import{subscribe as e}from"valtio";import{get as t,set as n}from"@hairy/utils";import{destr as r}from"destr";import{generateStructureId as i}from"structure-id";function a({hydrate:a=!0}={}){return o=>{let{persist:s,getters:c}=o.options,{$state:l}=o.store;if(!s)return;let u=s===!0?{}:s,d=u.key||i(l),f=u.storage??(typeof localStorage<`u`?localStorage:void 0);if(!f?.getItem||!f?.setItem)return;let p=!1;function m(e){let t=r(e);t&&typeof t==`object`&&(Object.keys(c||{}).forEach(e=>Reflect.deleteProperty(t,e)),Object.assign(l,t)),p=!0}function h(){let e=f.getItem(d);e instanceof Promise?e.then(m):m(e)}function g(){e(l,()=>{if(!p)return;let e=(u.paths||Object.keys(l)).reduce((e,r)=>n(e,r,t(l,r)),{});f.setItem(d,JSON.stringify(e))})}o.store.$persist={mount:h},a&&h(),g()}}export{a as persist};
1
+ import{subscribe as e}from"valtio";import{get as t,set as n}from"@hairy/utils";import{destr as r}from"destr";import{generateStructureId as i}from"structure-id";function a({hydrate:a=!0}={}){return o=>{let{persist:s,getters:c}=o.options,{$state:l}=o.store;if(o.store.$persist?.unmount?.(),!s)return;let u=s===!0?{}:s,d=u.key||i(l),f=u.storage??(typeof localStorage<`u`?localStorage:void 0);if(!f?.getItem||!f?.setItem)return;let p=o.store.$persist?.meta??{mounted:!1,hydrated:!1};function m(e){let t=r(e);t&&typeof t==`object`&&(Object.keys(c||{}).forEach(e=>Reflect.deleteProperty(t,e)),Object.assign(l,t)),p.hydrated=!0}function h(){p.mounted=!0;let e=f.getItem(d);e instanceof Promise?e.then(m):m(e)}function g(){p.unsubscribe?.(),p.unsubscribe=void 0}function _(){g(),p.unsubscribe=e(l,()=>{if(!p.hydrated)return;let e=(u.paths||Object.keys(l)).reduce((e,r)=>n(e,r,t(l,r)),{});f.setItem(d,JSON.stringify(e))})}o.store.$persist={mount:h,unmount:g,meta:p},a&&!p.mounted&&h(),_()}}export{a as persist};
@@ -12,10 +12,17 @@ interface PersistentOptions<S extends object> {
12
12
  storage?: Storage;
13
13
  paths?: DeepKeys<S>[];
14
14
  }
15
+ interface PersistentMeta {
16
+ mounted: boolean;
17
+ hydrated: boolean;
18
+ unsubscribe?: () => void;
19
+ }
15
20
  interface PersistentStore {
16
21
  $persist: {
17
22
  mount: () => void;
23
+ unmount: () => void;
24
+ meta: PersistentMeta;
18
25
  };
19
26
  }
20
27
  //#endregion
21
- export { DeepKeys, PersistentOptions, PersistentStore, Storage };
28
+ export { DeepKeys, PersistentMeta, PersistentOptions, PersistentStore, Storage };
@@ -7,10 +7,10 @@ type Getters<S = any> = Record<string, (this: S) => any>;
7
7
  type ActionsOmitThisParameter<A extends Actions<any>> = { [K in keyof A]: (...args: Parameters<A[K]>) => ReturnType<A[K]> };
8
8
  type GettersReturnType<G extends Getters<any>> = { [K in keyof G]: ReturnType<G[K]> };
9
9
  interface StoreDefineOptions<S> {}
10
- interface StoreDefine<S extends object, A, G extends Getters<any>> extends StoreDefineOptions<S> {
10
+ interface StoreDefine<S extends object, A extends object, G extends Getters<any>> extends StoreDefineOptions<S> {
11
11
  state: (() => S) | S;
12
- actions?: A & ThisType<A & S>;
13
- getters?: G & ThisType<S>;
12
+ actions?: A & ThisType<A & S & GettersReturnType<G>>;
13
+ getters?: G & ThisType<S & GettersReturnType<G>>;
14
14
  }
15
15
  interface Signal<S, G extends Getters<S>> {
16
16
  <T>(fn: (state: S & GettersReturnType<G>) => T): ReactElement;
@@ -27,7 +27,7 @@ interface Patch<S, G extends Getters<S>> {
27
27
  (patch: Partial<S> | ((state: S & GettersReturnType<G>) => void)): void;
28
28
  }
29
29
  interface StoreOptions {}
30
- type Store<S, A extends Actions<S>, G extends Getters<S>> = {
30
+ type Store<S, A extends Actions<S> = {}, G extends Getters<S> = {}> = {
31
31
  $subscribe: Subscribe<S, G>;
32
32
  $subscribeKey: SubscribeKey<S, G>;
33
33
  $patch: Patch<S, G>;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "valtio-define",
3
3
  "type": "module",
4
- "version": "1.1.5",
4
+ "version": "1.2.1",
5
5
  "description": "⚡quickly create a fully functional and robust Valtio factory",
6
6
  "author": "Hairyf <wwu710632@gmail.com>",
7
7
  "license": "MIT",