@yakocloud/state-vocab 4.0.1 → 4.0.3
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 +133 -91
- package/dist/client.cjs.js +1 -1
- package/dist/client.es.js +119 -75
- package/dist/constants-BB1YAX6c.mjs +8 -0
- package/dist/constants-CbsduCZ7.js +1 -0
- package/dist/index.cjs.js +1 -1
- package/dist/index.es.js +15 -14
- package/dist/provider-client-B4XQ24JB.js +1 -0
- package/dist/{provider.client-CtAC9tPr.mjs → provider-client-C2Aw0Lmi.mjs} +2 -2
- package/dist/server.cjs.js +1 -1
- package/dist/server.es.js +32 -26
- package/dist/types/client.d.ts +1 -1
- package/dist/types/context.client.d.ts +2 -2
- package/dist/types/server.d.ts +0 -1
- package/dist/types/setup.client.utils.d.ts +12 -0
- package/dist/types/setup.server.d.ts +6 -2
- package/dist/utils-0CTNJ4ZE.js +3 -0
- package/dist/utils-xV3x3fTc.mjs +57 -0
- package/package.json +1 -1
- package/dist/provider.client--OPImdtY.js +0 -1
- package/dist/types/state.client.utils.d.ts +0 -2
- package/dist/utils-33NqsZoR.js +0 -3
- package/dist/utils-t8tYdd6B.mjs +0 -63
package/README.md
CHANGED
|
@@ -117,7 +117,7 @@ npm install @yakocloud/state-vocab react react-dom
|
|
|
117
117
|
|
|
118
118
|
## Quick Start
|
|
119
119
|
|
|
120
|
-
|
|
120
|
+
Define your storage tree once (`setupStorage`/`defineState`), call `clientify` to attach React hooks. If you use react server components (RSC) wrap your app with `StateVocabProvider` at the root and call `serverify` to attach RSC-methods. Use state anywhere in the tree
|
|
121
121
|
|
|
122
122
|
Library SSR-requirements:
|
|
123
123
|
- `Per-request store`: A Next.js server can handle multiple requests simultaneously. This means that the store should be created per request and should not be shared across requests.
|
|
@@ -125,11 +125,11 @@ Library SSR-requirements:
|
|
|
125
125
|
|
|
126
126
|
```tsx
|
|
127
127
|
import { setupStorage, defineState } from '@yakocloud/state-vocab'
|
|
128
|
-
import { clientify
|
|
128
|
+
import { clientify } from '@yakocloud/state-vocab/client'
|
|
129
129
|
|
|
130
130
|
type Theme = 'Dark' | 'White' | 'System'
|
|
131
131
|
|
|
132
|
-
const storage =
|
|
132
|
+
const storage = setupStorage({
|
|
133
133
|
path: {
|
|
134
134
|
to: {
|
|
135
135
|
theme: defineState<Theme>({
|
|
@@ -138,18 +138,14 @@ const storage = clientify(setupStorage({
|
|
|
138
138
|
}),
|
|
139
139
|
},
|
|
140
140
|
},
|
|
141
|
-
}
|
|
141
|
+
}, {
|
|
142
|
+
ssr: false // by default true
|
|
143
|
+
})
|
|
142
144
|
|
|
143
|
-
|
|
144
|
-
return (
|
|
145
|
-
<StateVocabProvider>
|
|
146
|
-
<Settings />
|
|
147
|
-
</StateVocabProvider>
|
|
148
|
-
)
|
|
149
|
-
}
|
|
145
|
+
const clientStorage = clientify(storage)
|
|
150
146
|
|
|
151
147
|
function Settings() {
|
|
152
|
-
const [theme, setTheme] =
|
|
148
|
+
const [theme, setTheme] = clientStorage.path.to.theme.useState()
|
|
153
149
|
|
|
154
150
|
return (
|
|
155
151
|
<select value={theme} onChange={(e) => setTheme(e.target.value as Theme)}>
|
|
@@ -161,37 +157,6 @@ function Settings() {
|
|
|
161
157
|
}
|
|
162
158
|
```
|
|
163
159
|
|
|
164
|
-
## Setup
|
|
165
|
-
|
|
166
|
-
### `StateVocabProvider`
|
|
167
|
-
|
|
168
|
-
All components that call `.useState()` must be descendants of `StateVocabProvider`. It creates an isolated `VocabStore` instance for its subtree — multiple providers can coexist in the same app without sharing state.
|
|
169
|
-
|
|
170
|
-
```tsx
|
|
171
|
-
import { StateVocabProvider } from '@yakocloud/state-vocab/client'
|
|
172
|
-
|
|
173
|
-
createRoot(document.getElementById('root')!).render(
|
|
174
|
-
<React.StrictMode>
|
|
175
|
-
<StateVocabProvider>
|
|
176
|
-
<App />
|
|
177
|
-
</StateVocabProvider>
|
|
178
|
-
</React.StrictMode>
|
|
179
|
-
)
|
|
180
|
-
```
|
|
181
|
-
|
|
182
|
-
You can mount multiple independent providers — each gets its own store:
|
|
183
|
-
|
|
184
|
-
```tsx
|
|
185
|
-
// Two isolated state trees — state does not bleed between them
|
|
186
|
-
<StateVocabProvider>
|
|
187
|
-
<WidgetA />
|
|
188
|
-
</StateVocabProvider>
|
|
189
|
-
|
|
190
|
-
<StateVocabProvider>
|
|
191
|
-
<WidgetB />
|
|
192
|
-
</StateVocabProvider>
|
|
193
|
-
```
|
|
194
|
-
|
|
195
160
|
## Core Concepts
|
|
196
161
|
|
|
197
162
|
### `defineState(options?)`
|
|
@@ -237,7 +202,7 @@ Wraps a nested object of `defineState()` nodes and injects dot-separated paths i
|
|
|
237
202
|
|---|---|---|---|
|
|
238
203
|
| `verbose` | `boolean \| undefined` | Log current state to the browser console on every change | `false` |
|
|
239
204
|
| `verbosePath` | `string \| undefined` | Narrow verbose logging to a specific subtree (dot-separated path). When set, only that subtree is logged instead of the entire state. TypeScript will autocomplete valid paths based on your tree. | `undefined` |
|
|
240
|
-
| `ssr` | `boolean \| undefined` | Defer storage reads until after hydration (Next.js / SSR) | `
|
|
205
|
+
| `ssr` | `boolean \| undefined` | Defer storage reads until after hydration (Next.js / SSR) | `true` |
|
|
241
206
|
|
|
242
207
|
```ts
|
|
243
208
|
const storage = setupStorage({
|
|
@@ -286,15 +251,90 @@ const storage = setupStorage({
|
|
|
286
251
|
preference: {
|
|
287
252
|
theme: defineState<Theme>({ storage: localStorage, defaultValue: 'Dark' }),
|
|
288
253
|
},
|
|
289
|
-
}
|
|
254
|
+
})
|
|
290
255
|
```
|
|
291
256
|
|
|
292
|
-
|
|
257
|
+
By default `ssr: true`:
|
|
293
258
|
- **Server & first client render** — always use `defaultValue`, storage is not read
|
|
294
259
|
- **After hydration** — `useLayoutEffect` fires synchronously before paint, reads storage and updates state
|
|
295
260
|
|
|
296
261
|
This guarantees the server and client produce identical markup, and the value from storage is applied without a visible flash.
|
|
297
262
|
|
|
263
|
+
### Next.js Pages Router (SSR without RSC)
|
|
264
|
+
|
|
265
|
+
If you use Next.js with the **Pages Router** (or any SSR setup without React Server Components), you still need `ssr: true` to prevent hydration mismatches — but you don't have server components to wrap with `StateVocabProvider` from `serverify`.
|
|
266
|
+
|
|
267
|
+
In this case, wrap your app with `StateVocabClientProvider` from `@yakocloud/state-vocab/client`. It creates an isolated `VocabStore` per render, preventing state from leaking between concurrent SSR requests.
|
|
268
|
+
|
|
269
|
+
```tsx
|
|
270
|
+
// pages/_app.tsx
|
|
271
|
+
import type { AppProps } from 'next/app'
|
|
272
|
+
import { StateVocabClientProvider } from '@yakocloud/state-vocab/client'
|
|
273
|
+
|
|
274
|
+
export default function App({ Component, pageProps }: AppProps) {
|
|
275
|
+
return (
|
|
276
|
+
<StateVocabClientProvider>
|
|
277
|
+
<Component {...pageProps} />
|
|
278
|
+
</StateVocabClientProvider>
|
|
279
|
+
)
|
|
280
|
+
}
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
Storage is still configured with `ssr: true` (the default):
|
|
284
|
+
|
|
285
|
+
```ts
|
|
286
|
+
// lib/storage.ts
|
|
287
|
+
import { setupStorage, defineState } from '@yakocloud/state-vocab'
|
|
288
|
+
import { clientify } from '@yakocloud/state-vocab/client'
|
|
289
|
+
|
|
290
|
+
const storage = setupStorage({
|
|
291
|
+
preference: {
|
|
292
|
+
theme: defineState<'Dark' | 'White' | 'System'>({
|
|
293
|
+
storage: localStorage,
|
|
294
|
+
defaultValue: 'Dark',
|
|
295
|
+
}),
|
|
296
|
+
},
|
|
297
|
+
// ssr: true is the default — storage reads are deferred until after hydration
|
|
298
|
+
})
|
|
299
|
+
|
|
300
|
+
export const clientStorage = clientify(storage)
|
|
301
|
+
```
|
|
302
|
+
|
|
303
|
+
Use `clientStorage` directly in any page or component — no additional wiring needed:
|
|
304
|
+
|
|
305
|
+
```tsx
|
|
306
|
+
// pages/settings.tsx
|
|
307
|
+
import { clientStorage } from '@/lib/storage'
|
|
308
|
+
|
|
309
|
+
export default function Settings() {
|
|
310
|
+
const [theme, setTheme] = clientStorage.preference.theme.useState()
|
|
311
|
+
|
|
312
|
+
return (
|
|
313
|
+
<select value={theme} onChange={(e) => setTheme(e.target.value as 'Dark' | 'White' | 'System')}>
|
|
314
|
+
<option value="Dark">Dark</option>
|
|
315
|
+
<option value="White">White</option>
|
|
316
|
+
<option value="System">System</option>
|
|
317
|
+
</select>
|
|
318
|
+
)
|
|
319
|
+
}
|
|
320
|
+
```
|
|
321
|
+
|
|
322
|
+
`StateVocabClientProvider` also accepts an optional `value` prop to pre-seed the store with server-fetched data (e.g., from `getServerSideProps`):
|
|
323
|
+
|
|
324
|
+
```tsx
|
|
325
|
+
// pages/_app.tsx
|
|
326
|
+
import type { AppProps } from 'next/app'
|
|
327
|
+
import { StateVocabClientProvider } from '@yakocloud/state-vocab/client'
|
|
328
|
+
|
|
329
|
+
export default function App({ Component, pageProps }: AppProps) {
|
|
330
|
+
return (
|
|
331
|
+
<StateVocabClientProvider value={pageProps.initialVocab}>
|
|
332
|
+
<Component {...pageProps} />
|
|
333
|
+
</StateVocabClientProvider>
|
|
334
|
+
)
|
|
335
|
+
}
|
|
336
|
+
```
|
|
337
|
+
|
|
298
338
|
### React Server Components (RSC)
|
|
299
339
|
|
|
300
340
|
For Next.js apps using the App Router, state-vocab provides dedicated server and client entry points that let you read state in async server components and pass it down to client components via `StateVocabProvider`.
|
|
@@ -304,8 +344,8 @@ For Next.js apps using the App Router, state-vocab provides dedicated server and
|
|
|
304
344
|
| Import path | Use in |
|
|
305
345
|
|---|---|
|
|
306
346
|
| `@yakocloud/state-vocab` | Shared files — `defineState`, `setupStorage` |
|
|
307
|
-
| `@yakocloud/state-vocab/server` | Server Components — `serverify
|
|
308
|
-
| `@yakocloud/state-vocab/client` | Client Components — `clientify` |
|
|
347
|
+
| `@yakocloud/state-vocab/server` | Server Components — `serverify` |
|
|
348
|
+
| `@yakocloud/state-vocab/client` | Client Components — `clientify`, `StateVocabClientProvider` |
|
|
309
349
|
|
|
310
350
|
**1. Define the shared storage schema** (used on both server and client):
|
|
311
351
|
|
|
@@ -323,7 +363,7 @@ export const storage = setupStorage({
|
|
|
323
363
|
city: defineState<string>(),
|
|
324
364
|
},
|
|
325
365
|
},
|
|
326
|
-
}
|
|
366
|
+
})
|
|
327
367
|
```
|
|
328
368
|
|
|
329
369
|
**2. Create server and client storage handles:**
|
|
@@ -351,7 +391,8 @@ export const clientStorage = clientify(storage)
|
|
|
351
391
|
```tsx
|
|
352
392
|
// app/page.tsx (Server Component)
|
|
353
393
|
import { serverStorage } from '@/storage.server'
|
|
354
|
-
|
|
394
|
+
|
|
395
|
+
const { StateVocabProvider } = serverStorage
|
|
355
396
|
|
|
356
397
|
export default async function Page() {
|
|
357
398
|
// Fetch data from DB / API
|
|
@@ -359,10 +400,10 @@ export default async function Page() {
|
|
|
359
400
|
|
|
360
401
|
return (
|
|
361
402
|
<StateVocabProvider
|
|
362
|
-
value={
|
|
403
|
+
value={{
|
|
363
404
|
user: { name: user.name, role: user.role },
|
|
364
405
|
person: { address: { city: user.city } },
|
|
365
|
-
}
|
|
406
|
+
}}
|
|
366
407
|
>
|
|
367
408
|
<UserInfo />
|
|
368
409
|
</StateVocabProvider>
|
|
@@ -398,35 +439,24 @@ export default function UserInfoClient() {
|
|
|
398
439
|
|
|
399
440
|
#### `serverify(storage)`
|
|
400
441
|
|
|
401
|
-
Converts a storage tree into its server-side counterpart. Each leaf gains a `.getState()` method that reads the value seeded into the nearest `StateVocabProvider`. Each namespace node (including the root) gains a `.
|
|
442
|
+
Converts a storage tree into its server-side counterpart. Each leaf gains a `.getState()` method that reads the value seeded into the nearest `StateVocabProvider`. Each namespace node (including the root) gains a `.seed()` method that returns the input wrapped under its full ancestor path. This method is optional for using. The result also exposes `StateVocabProvider` — a server-aware provider that accepts a plain object `value` prop to pre-seed the store.
|
|
402
443
|
|
|
403
|
-
**`.
|
|
444
|
+
**`.seed()` syntax:**
|
|
404
445
|
|
|
405
446
|
```ts
|
|
406
|
-
// Full tree at once — root .
|
|
407
|
-
serverStorage.
|
|
447
|
+
// Full tree at once — root .seed() returns input as-is
|
|
448
|
+
serverStorage.seed({ user: { name: 'Alice', role: 'Admin' } })
|
|
408
449
|
// → { user: { name: 'Alice', role: 'Admin' } }
|
|
409
450
|
|
|
410
451
|
// Single namespace — wraps input under its key
|
|
411
|
-
serverStorage.user.
|
|
452
|
+
serverStorage.user.seed({ name: 'Alice', role: 'Admin' })
|
|
412
453
|
// → { user: { name: 'Alice', role: 'Admin' } }
|
|
413
454
|
|
|
414
455
|
// Nested namespace — wraps up to the root
|
|
415
|
-
serverStorage.person.address.
|
|
456
|
+
serverStorage.person.address.seed({ city: 'NY' })
|
|
416
457
|
// → { person: { address: { city: 'NY' } } }
|
|
417
458
|
```
|
|
418
459
|
|
|
419
|
-
All three forms return a value ready to pass as `StateVocabProvider`'s `value` prop. They can be combined by spreading:
|
|
420
|
-
|
|
421
|
-
```tsx
|
|
422
|
-
<StateVocabProvider
|
|
423
|
-
value={{
|
|
424
|
-
...serverStorage.user.set({ name: 'Alice', role: 'Admin' }),
|
|
425
|
-
...serverStorage.person.address.set({ city: 'NY' }),
|
|
426
|
-
}}
|
|
427
|
-
>
|
|
428
|
-
```
|
|
429
|
-
|
|
430
460
|
**`node.getState()`** reads the value for that leaf from the surrounding `StateVocabProvider`. Throws if called outside one.
|
|
431
461
|
|
|
432
462
|
#### `clientify(storage)`
|
|
@@ -521,11 +551,11 @@ const storage = setupStorage({
|
|
|
521
551
|
import React from 'react'
|
|
522
552
|
import { createRoot } from 'react-dom/client'
|
|
523
553
|
import { setupStorage, defineState } from '@yakocloud/state-vocab'
|
|
524
|
-
import { clientify
|
|
554
|
+
import { clientify } from '@yakocloud/state-vocab/client'
|
|
525
555
|
|
|
526
556
|
type Theme = 'Dark' | 'White' | 'System'
|
|
527
557
|
|
|
528
|
-
const storage =
|
|
558
|
+
const storage = setupStorage({
|
|
529
559
|
preference: {
|
|
530
560
|
theme: defineState<Theme>({ storage: localStorage, defaultValue: 'Dark' }),
|
|
531
561
|
nightMode: defineState({ storage: sessionStorage, defaultValue: false }),
|
|
@@ -547,11 +577,15 @@ const storage = clientify(setupStorage({
|
|
|
547
577
|
storage: localStorage,
|
|
548
578
|
}),
|
|
549
579
|
},
|
|
550
|
-
}
|
|
580
|
+
}, {
|
|
581
|
+
ssr: false // by default true
|
|
582
|
+
})
|
|
583
|
+
|
|
584
|
+
const clientStorage = clientify(storage)
|
|
551
585
|
|
|
552
586
|
// Root — initializes shared state for the whole subtree
|
|
553
587
|
function Page() {
|
|
554
|
-
|
|
588
|
+
clientStorage.demo.pageProps.useState({
|
|
555
589
|
defaultValue: { title: 'Hello', count: 42 },
|
|
556
590
|
})
|
|
557
591
|
|
|
@@ -560,15 +594,15 @@ function Page() {
|
|
|
560
594
|
|
|
561
595
|
// Deep child — reads without re-specifying defaults
|
|
562
596
|
function PageHeader() {
|
|
563
|
-
const [pageProps] =
|
|
597
|
+
const [pageProps] = clientStorage.demo.pageProps.useState()
|
|
564
598
|
return <h1>{pageProps.title} ({pageProps.count})</h1>
|
|
565
599
|
}
|
|
566
600
|
|
|
567
601
|
function Dashboard() {
|
|
568
|
-
const [theme, setTheme] =
|
|
569
|
-
const [nightMode, setNightMode] =
|
|
570
|
-
const [counter, setCounter, resetCounter] =
|
|
571
|
-
const [note, setNote] =
|
|
602
|
+
const [theme, setTheme] = clientStorage.preference.theme.useState()
|
|
603
|
+
const [nightMode, setNightMode] = clientStorage.preference.nightMode.useState()
|
|
604
|
+
const [counter, setCounter, resetCounter] = clientStorage.stats.counter.useState()
|
|
605
|
+
const [note, setNote] = clientStorage.personal.note.useState({
|
|
572
606
|
delayedSet: 500,
|
|
573
607
|
onSet: (v) => console.log('Saving note:', v),
|
|
574
608
|
})
|
|
@@ -607,9 +641,7 @@ function Dashboard() {
|
|
|
607
641
|
|
|
608
642
|
createRoot(document.getElementById('root')!).render(
|
|
609
643
|
<React.StrictMode>
|
|
610
|
-
<
|
|
611
|
-
<Page />
|
|
612
|
-
</StateVocabProvider>
|
|
644
|
+
<Page />
|
|
613
645
|
</React.StrictMode>
|
|
614
646
|
)
|
|
615
647
|
```
|
|
@@ -632,42 +664,52 @@ createRoot(document.getElementById('root')!).render(
|
|
|
632
664
|
|---|---|---|
|
|
633
665
|
| `verbose` | `boolean \| undefined` | `false` |
|
|
634
666
|
| `verbosePath` | `Path<T> \| undefined` | `undefined` |
|
|
635
|
-
| `ssr` | `boolean \| undefined` | `
|
|
667
|
+
| `ssr` | `boolean \| undefined` | `true` |
|
|
636
668
|
|
|
637
669
|
Returns a proxied copy of `tree` with paths injected into all leaf nodes.
|
|
638
670
|
|
|
639
671
|
### `StateVocabProvider`
|
|
640
672
|
|
|
641
|
-
A React context provider that initializes a `VocabStore` for its subtree.
|
|
673
|
+
A React context provider that initializes a `VocabStore` for its subtree. Only required in RSC / Next.js App Router contexts (where `ssr: true`). For standard SPAs without SSR, no provider is needed — hooks use a module-level store automatically.
|
|
674
|
+
|
|
675
|
+
In RSC contexts, `StateVocabProvider` is available on the `serverify()` result — it accepts an optional `value` prop to pre-seed the store with server-fetched data:
|
|
642
676
|
|
|
643
677
|
```tsx
|
|
644
|
-
|
|
678
|
+
const { StateVocabProvider } = serverStorage
|
|
679
|
+
|
|
680
|
+
<StateVocabProvider value={{ user: { name: 'Alice' } }}>
|
|
645
681
|
<App />
|
|
646
682
|
</StateVocabProvider>
|
|
647
683
|
```
|
|
648
684
|
|
|
649
|
-
|
|
685
|
+
### `StateVocabClientProvider`
|
|
686
|
+
|
|
687
|
+
A client-only provider for SSR setups **without** React Server Components (e.g. Next.js Pages Router). Import from `@yakocloud/state-vocab/client` and place it at your app root to ensure per-request store isolation. Accepts an optional `value` prop to pre-seed the store.
|
|
650
688
|
|
|
651
689
|
```tsx
|
|
652
|
-
|
|
690
|
+
import { StateVocabClientProvider } from '@yakocloud/state-vocab/client'
|
|
691
|
+
|
|
692
|
+
<StateVocabClientProvider value={initialVocab}>
|
|
653
693
|
<App />
|
|
654
|
-
</
|
|
694
|
+
</StateVocabClientProvider>
|
|
655
695
|
```
|
|
656
696
|
|
|
657
697
|
### `serverify<T>(storage: T)`
|
|
658
698
|
|
|
659
699
|
Converts a storage tree to its server-side counterpart. Available from `@yakocloud/state-vocab/server`.
|
|
660
700
|
|
|
661
|
-
Each leaf gains `.getState()` — reads the value from the nearest `StateVocabProvider`. Each namespace node gains `.
|
|
701
|
+
Each leaf gains `.getState()` — reads the value from the nearest `StateVocabProvider`. Each namespace node gains `.seed()`, which returns the input wrapped under its full ancestor path. The result also includes `StateVocabProvider` — use it instead of importing from `@yakocloud/state-vocab/server`.
|
|
662
702
|
|
|
663
703
|
```ts
|
|
664
704
|
import { serverify } from '@yakocloud/state-vocab/server'
|
|
665
705
|
const serverStorage = serverify(storage)
|
|
666
706
|
|
|
707
|
+
const { StateVocabProvider } = serverStorage // server-aware provider
|
|
708
|
+
|
|
667
709
|
serverStorage.user.name.getState() // reads "user.name" from context
|
|
668
|
-
serverStorage.user.
|
|
669
|
-
serverStorage.person.address.
|
|
670
|
-
serverStorage.
|
|
710
|
+
serverStorage.user.seed({ name: 'Alice' }) // → { user: { name: 'Alice' } }
|
|
711
|
+
serverStorage.person.address.seed({ city: 'NY' }) // → { person: { address: { city: 'NY' } } }
|
|
712
|
+
serverStorage.seed({ user: { name: 'Alice' } }) // → { user: { name: 'Alice' } } (identity)
|
|
671
713
|
```
|
|
672
714
|
|
|
673
715
|
### `clientify<T>(storage: T)`
|
package/dist/client.cjs.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use client";"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const
|
|
1
|
+
"use client";"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const u=require("react"),v=require("./constants-CbsduCZ7.js"),a=require("./utils-0CTNJ4ZE.js"),V=require("./provider-client-B4XQ24JB.js");function D(t,e,n=[]){return u.useMemo(()=>a.debounce(t,e),n)}const g=t=>{const{vocabStore:e,storage:n,statePath:o,value:i,deserialize:S,serialize:l}=t,f=n.getItem(o);f===null?a.isValueDefined(i)&&n.setItem(o,l(i)):e.set(o,S(f))},z=typeof window>"u",O=z?u.useEffect:u.useLayoutEffect,m=new V.VocabStore,A="Make sure your component is wrapped in StateVocabProvider (RSC) or disable ssr option in setupStorage for SPA (RCC only)";function I(t){t??={};const e=z?void 0:a.valueOrFactory(t.storage),n=a.valueOrFactory(t.defaultValue),o=t.bidirectional,i=this[v.STATE_PATH],S=this[v.STATE_VERBOSE],l=this[v.STATE_VERBOSE_PATH],f=this[v.STATE_SSR];let s=V.useStateVocabClientContext({verbose:S});if(!(s instanceof V.VocabStore)){if(f)throw new Error(A);s=m}const d=t.serialize??JSON.stringify,c=t.deserialize??JSON.parse,E=D(t.onSet??(()=>{}),t.delayedSet,[]),y=u.useRef(void 0),C=u.useRef(!1);if(!C.current){C.current=!0;let r=s.get(i);a.isValueDefined(r)||(r=n,a.isValueDefined(r)&&s.set(i,r)),!f&&e&&g({vocabStore:s,storage:e,statePath:i,value:r,serialize:d,deserialize:c})}const h=u.useSyncExternalStore(s.subscribe.bind(s),s.getClientSnapshot.bind(s),s.getServerSnapshot.bind(s));if(S)if(l){const r=a.get(h,l);r&&a.logStyled(r)}else a.logStyled(h);const T=a.get(h,i,n);y.current=T,O(()=>{!f||!e||g({vocabStore:s,storage:e,statePath:i,value:T,serialize:d,deserialize:c})},[]);const w=u.useEffectEvent(r=>{if(r.key!==i)return;const b=r.newValue,R=(b===null?null:c(b))??n;a.isValueDefined(R)&&(s.set(i,R),E(R,y.current))});u.useEffect(()=>{if(o)return window.addEventListener("storage",w),()=>window.removeEventListener("storage",w)},[o]);const p=u.useCallback(r=>{const b=a.isTransformer(r)?r(y.current):r;s.set(i,b),E(b,y.current),e&&e.setItem(i,d(b))},[s,i,E,e,d]),_=u.useCallback(()=>{const r=n;if(!a.isValueDefined(r)){e?.removeItem(i);return}s.set(i,r),E(r,y.current),e&&e.setItem(i,d(r))},[n,s,i,E,e,d]);return[T,p,_]}function k(t){t??={};const e=z?void 0:a.valueOrFactory(t.storage),n=a.valueOrFactory(t.defaultValue),o=this[v.STATE_PATH],i=this[v.STATE_VERBOSE],S=this[v.STATE_SSR];let l=V.useStateVocabClientContext({verbose:i});if(!(l instanceof V.VocabStore)){if(S)throw new Error(A);l=m}const f=t.serialize??JSON.stringify,s=t.deserialize??JSON.parse,d=u.useRef(!1);let c;d.current||(d.current=!0,c=l.get(o),a.isValueDefined(c)||(c=n,a.isValueDefined(c)&&l.set(o,c)),!S&&e&&g({vocabStore:l,storage:e,statePath:o,value:c,serialize:f,deserialize:s})),O(()=>{!S||!e||g({vocabStore:l,storage:e,statePath:o,value:c,serialize:f,deserialize:s})},[])}function q(t){return typeof t=="object"&&t!==null&&"clientSlot"in t}function P(t){const e={};for(const n in t){const o=t[n];q(o)?(e[n]=o.clientSlot({useState(...i){return I.apply(this,i)},useInitialState(...i){k.apply(this,i)}}),delete e[n].serverSlot,delete e[n].clientSlot):o!==null&&typeof o=="object"?e[n]=P(o):e[n]=o}return e}exports.StateVocabClientProvider=V.StateVocabClientProvider;exports.clientify=P;
|
package/dist/client.es.js
CHANGED
|
@@ -1,107 +1,151 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import { useMemo as
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
2
|
+
import { useMemo as x, useRef as y, useSyncExternalStore as B, useEffectEvent as D, useEffect as A, useCallback as T, useLayoutEffect as H } from "react";
|
|
3
|
+
import { S as I, a as O, b as _, c as F } from "./constants-BB1YAX6c.mjs";
|
|
4
|
+
import { a as d, d as G, v as g, g as C, l as P, i as q } from "./utils-xV3x3fTc.mjs";
|
|
5
|
+
import { V as z, u as k } from "./provider-client-C2Aw0Lmi.mjs";
|
|
6
|
+
import { S as ie } from "./provider-client-C2Aw0Lmi.mjs";
|
|
7
|
+
function K(t, e, n = []) {
|
|
8
|
+
return x(
|
|
9
|
+
() => G(t, e),
|
|
9
10
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
10
11
|
n
|
|
11
12
|
);
|
|
12
13
|
}
|
|
13
|
-
const
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
14
|
+
const E = (t) => {
|
|
15
|
+
const {
|
|
16
|
+
vocabStore: e,
|
|
17
|
+
storage: n,
|
|
18
|
+
statePath: o,
|
|
19
|
+
value: s,
|
|
20
|
+
deserialize: f,
|
|
21
|
+
serialize: a
|
|
22
|
+
} = t, c = n.getItem(o);
|
|
23
|
+
c === null ? d(s) && n.setItem(o, a(s)) : e.set(o, f(c));
|
|
24
|
+
}, p = typeof window > "u", J = p ? A : H, L = new z(), N = "Make sure your component is wrapped in StateVocabProvider (RSC) or disable ssr option in setupStorage for SPA (RCC only)";
|
|
25
|
+
function Q(t) {
|
|
26
|
+
t ??= {};
|
|
27
|
+
const e = p ? void 0 : g(t.storage), n = g(t.defaultValue), o = t.bidirectional, s = this[I], f = this[O], a = this[F], c = this[_];
|
|
28
|
+
let r = k({ verbose: f });
|
|
29
|
+
if (!(r instanceof z)) {
|
|
30
|
+
if (c)
|
|
31
|
+
throw new Error(N);
|
|
32
|
+
r = L;
|
|
33
|
+
}
|
|
34
|
+
const u = t.serialize ?? JSON.stringify, l = t.deserialize ?? JSON.parse, v = K(
|
|
35
|
+
t.onSet ?? (() => {
|
|
24
36
|
}),
|
|
25
|
-
|
|
37
|
+
t.delayedSet,
|
|
26
38
|
[]
|
|
27
|
-
),
|
|
28
|
-
if (!
|
|
29
|
-
|
|
30
|
-
let
|
|
31
|
-
d(
|
|
39
|
+
), b = y(void 0), w = y(!1);
|
|
40
|
+
if (!w.current) {
|
|
41
|
+
w.current = !0;
|
|
42
|
+
let i = r.get(s);
|
|
43
|
+
d(i) || (i = n, d(i) && r.set(s, i)), !c && e && E({
|
|
44
|
+
vocabStore: r,
|
|
45
|
+
storage: e,
|
|
46
|
+
statePath: s,
|
|
47
|
+
value: i,
|
|
48
|
+
serialize: u,
|
|
49
|
+
deserialize: l
|
|
50
|
+
});
|
|
32
51
|
}
|
|
33
|
-
const
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
52
|
+
const h = B(
|
|
53
|
+
r.subscribe.bind(r),
|
|
54
|
+
r.getClientSnapshot.bind(r),
|
|
55
|
+
r.getServerSnapshot.bind(r)
|
|
37
56
|
);
|
|
38
|
-
if (
|
|
39
|
-
if (
|
|
40
|
-
const
|
|
41
|
-
|
|
57
|
+
if (f)
|
|
58
|
+
if (a) {
|
|
59
|
+
const i = C(h, a);
|
|
60
|
+
i && P(i);
|
|
42
61
|
} else
|
|
43
|
-
|
|
44
|
-
const
|
|
45
|
-
|
|
46
|
-
!
|
|
62
|
+
P(h);
|
|
63
|
+
const m = C(h, s, n);
|
|
64
|
+
b.current = m, J(() => {
|
|
65
|
+
!c || !e || E({
|
|
66
|
+
vocabStore: r,
|
|
67
|
+
storage: e,
|
|
68
|
+
statePath: s,
|
|
69
|
+
value: m,
|
|
70
|
+
serialize: u,
|
|
71
|
+
deserialize: l
|
|
72
|
+
});
|
|
47
73
|
}, []);
|
|
48
|
-
const
|
|
49
|
-
if (
|
|
74
|
+
const R = D((i) => {
|
|
75
|
+
if (i.key !== s)
|
|
50
76
|
return;
|
|
51
|
-
const
|
|
52
|
-
d(
|
|
77
|
+
const S = i.newValue, V = (S === null ? null : l(S)) ?? n;
|
|
78
|
+
d(V) && (r.set(s, V), v(V, b.current));
|
|
53
79
|
});
|
|
54
80
|
A(() => {
|
|
55
81
|
if (o)
|
|
56
|
-
return window.addEventListener("storage",
|
|
82
|
+
return window.addEventListener("storage", R), () => window.removeEventListener("storage", R);
|
|
57
83
|
}, [o]);
|
|
58
|
-
const
|
|
59
|
-
const
|
|
60
|
-
|
|
61
|
-
}, [
|
|
62
|
-
const
|
|
63
|
-
if (!d(
|
|
64
|
-
e?.removeItem(
|
|
84
|
+
const M = T((i) => {
|
|
85
|
+
const S = q(i) ? i(b.current) : i;
|
|
86
|
+
r.set(s, S), v(S, b.current), e && e.setItem(s, u(S));
|
|
87
|
+
}, [r, s, v, e, u]), j = T(() => {
|
|
88
|
+
const i = n;
|
|
89
|
+
if (!d(i)) {
|
|
90
|
+
e?.removeItem(s);
|
|
65
91
|
return;
|
|
66
92
|
}
|
|
67
|
-
|
|
68
|
-
}, [n,
|
|
93
|
+
r.set(s, i), v(i, b.current), e && e.setItem(s, u(i));
|
|
94
|
+
}, [n, r, s, v, e, u]);
|
|
69
95
|
return [
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
96
|
+
m,
|
|
97
|
+
M,
|
|
98
|
+
j
|
|
73
99
|
];
|
|
74
100
|
}
|
|
75
|
-
function
|
|
76
|
-
|
|
77
|
-
const e = p ? void 0 :
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
101
|
+
function U(t) {
|
|
102
|
+
t ??= {};
|
|
103
|
+
const e = p ? void 0 : g(t.storage), n = g(t.defaultValue), o = this[I], s = this[O], f = this[_];
|
|
104
|
+
let a = k({ verbose: s });
|
|
105
|
+
if (!(a instanceof z)) {
|
|
106
|
+
if (f)
|
|
107
|
+
throw new Error(N);
|
|
108
|
+
a = L;
|
|
109
|
+
}
|
|
110
|
+
const c = t.serialize ?? JSON.stringify, r = t.deserialize ?? JSON.parse, u = y(!1);
|
|
111
|
+
let l;
|
|
112
|
+
u.current || (u.current = !0, l = a.get(o), d(l) || (l = n, d(l) && a.set(o, l)), !f && e && E({
|
|
113
|
+
vocabStore: a,
|
|
114
|
+
storage: e,
|
|
115
|
+
statePath: o,
|
|
116
|
+
value: l,
|
|
117
|
+
serialize: c,
|
|
118
|
+
deserialize: r
|
|
119
|
+
})), J(() => {
|
|
120
|
+
!f || !e || E({
|
|
121
|
+
vocabStore: a,
|
|
122
|
+
storage: e,
|
|
123
|
+
statePath: o,
|
|
124
|
+
value: l,
|
|
125
|
+
serialize: c,
|
|
126
|
+
deserialize: r
|
|
127
|
+
});
|
|
84
128
|
}, []);
|
|
85
129
|
}
|
|
86
|
-
function
|
|
87
|
-
return typeof
|
|
130
|
+
function W(t) {
|
|
131
|
+
return typeof t == "object" && t !== null && "clientSlot" in t;
|
|
88
132
|
}
|
|
89
|
-
function
|
|
133
|
+
function X(t) {
|
|
90
134
|
const e = {};
|
|
91
|
-
for (const n in
|
|
92
|
-
const o =
|
|
93
|
-
|
|
94
|
-
useState(...
|
|
95
|
-
return
|
|
135
|
+
for (const n in t) {
|
|
136
|
+
const o = t[n];
|
|
137
|
+
W(o) ? (e[n] = o.clientSlot({
|
|
138
|
+
useState(...s) {
|
|
139
|
+
return Q.apply(this, s);
|
|
96
140
|
},
|
|
97
|
-
useInitialState(...
|
|
98
|
-
|
|
141
|
+
useInitialState(...s) {
|
|
142
|
+
U.apply(this, s);
|
|
99
143
|
}
|
|
100
|
-
}), delete e[n].serverSlot, delete e[n].clientSlot) : o !== null && typeof o == "object" ? e[n] =
|
|
144
|
+
}), delete e[n].serverSlot, delete e[n].clientSlot) : o !== null && typeof o == "object" ? e[n] = X(o) : e[n] = o;
|
|
101
145
|
}
|
|
102
146
|
return e;
|
|
103
147
|
}
|
|
104
148
|
export {
|
|
105
|
-
|
|
106
|
-
|
|
149
|
+
ie as StateVocabClientProvider,
|
|
150
|
+
X as clientify
|
|
107
151
|
};
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
const s = /* @__PURE__ */ Symbol("state-def"), t = /* @__PURE__ */ Symbol("state-path"), S = /* @__PURE__ */ Symbol("state-verbose"), a = /* @__PURE__ */ Symbol("state-verbose-path"), o = /* @__PURE__ */ Symbol("state-ssr");
|
|
2
|
+
export {
|
|
3
|
+
t as S,
|
|
4
|
+
S as a,
|
|
5
|
+
o as b,
|
|
6
|
+
a as c,
|
|
7
|
+
s as d
|
|
8
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";const T=Symbol("state-def"),S=Symbol("state-path"),E=Symbol("state-verbose"),t=Symbol("state-verbose-path"),s=Symbol("state-ssr");exports.STATE_DEFINITION=T;exports.STATE_PATH=S;exports.STATE_SSR=s;exports.STATE_VERBOSE=E;exports.STATE_VERBOSE_PATH=t;
|
package/dist/index.cjs.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const r=require("./constants-CbsduCZ7.js"),h=require("./utils-0CTNJ4ZE.js");function z(t={}){return{[r.STATE_DEFINITION]:!0,[r.STATE_PATH]:"",[r.STATE_VERBOSE]:!1,[r.STATE_VERBOSE_PATH]:"",[r.STATE_SSR]:!1,serverSlot(a){return Object.assign(this,{getState(...e){return a.getState.apply(this,e)}})},clientSlot(a){return Object.assign(this,{useState(e){return e??={},a.useState.apply(this,[{defaultValue:h.valueOrFactory(e.defaultValue)??h.valueOrFactory(t.defaultValue),bidirectional:e.bidirectional??t.bidirectional,storage:e.storage??t.storage,serialize:t.serialize??JSON.stringify,deserialize:t.deserialize??JSON.parse,delayedSet:e.delayedSet,onSet(...f){e.onSet&&e.onSet(...f)}}])},useInitialState(e){a.useInitialState.apply(this,[{defaultValue:e.defaultValue,storage:t.storage,serialize:t.serialize,deserialize:t.deserialize}])}})},toString(){return this[r.STATE_PATH]}}}function y(t,a){const{path:e="",verbose:f,verbosePath:A,ssr:b,cache:c}=a;let s=c.proxy.get(t);s||(s=new Map,c.proxy.set(t,s));const o=s.get(e);if(o)return o;const d=new Proxy(t,{get(P,T){const l=P[T],S=e?`${e}.${String(T)}`:String(T);if(l&&typeof l=="object"&&r.STATE_DEFINITION in l){const i=l;let n=c.leaf.get(i);n||(n=new Map,c.leaf.set(i,n));const g=n.get(S);if(g)return g;const _=Reflect.ownKeys(i).filter(u=>typeof i[u]=="function"),v=Object.fromEntries(_.map(u=>[u,(...V)=>i[u].call({...i,[r.STATE_PATH]:S,[r.STATE_VERBOSE]:f,[r.STATE_VERBOSE_PATH]:A,[r.STATE_SSR]:b},...V)])),E={...i,...v};return n.set(S,E),E}return l&&typeof l=="object"?y(l,{...a,path:S}):l}});return s.set(e,d),d}function I(t,a){return y(t,{...a,ssr:a?.ssr??!0,verbosePath:a?.verbosePath??"",cache:{proxy:new WeakMap,leaf:new WeakMap}})}exports.defineState=z;exports.setupStorage=I;
|
package/dist/index.es.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import { S as d,
|
|
2
|
-
|
|
1
|
+
import { S as d, b as T, c as E, a as P, d as v } from "./constants-BB1YAX6c.mjs";
|
|
2
|
+
import { v as b } from "./utils-xV3x3fTc.mjs";
|
|
3
|
+
function M(t = {}) {
|
|
3
4
|
return {
|
|
4
5
|
[v]: !0,
|
|
5
6
|
// marks this object as a leaf in the router tree
|
|
@@ -62,10 +63,10 @@ function z(t, a) {
|
|
|
62
63
|
} = a;
|
|
63
64
|
let s = n.proxy.get(t);
|
|
64
65
|
s || (s = /* @__PURE__ */ new Map(), n.proxy.set(t, s));
|
|
65
|
-
const
|
|
66
|
-
if (
|
|
67
|
-
return
|
|
68
|
-
const
|
|
66
|
+
const o = s.get(e);
|
|
67
|
+
if (o)
|
|
68
|
+
return o;
|
|
69
|
+
const h = new Proxy(t, {
|
|
69
70
|
get(V, u) {
|
|
70
71
|
const r = V[u], c = e ? `${e}.${String(u)}` : String(u);
|
|
71
72
|
if (r && typeof r == "object" && v in r) {
|
|
@@ -77,10 +78,10 @@ function z(t, a) {
|
|
|
77
78
|
return g;
|
|
78
79
|
const j = Reflect.ownKeys(l).filter(
|
|
79
80
|
(f) => typeof l[f] == "function"
|
|
80
|
-
),
|
|
81
|
+
), m = Object.fromEntries(
|
|
81
82
|
j.map((f) => [
|
|
82
83
|
f,
|
|
83
|
-
(...
|
|
84
|
+
(...w) => l[f].call(
|
|
84
85
|
{
|
|
85
86
|
...l,
|
|
86
87
|
[d]: c,
|
|
@@ -88,10 +89,10 @@ function z(t, a) {
|
|
|
88
89
|
[E]: x,
|
|
89
90
|
[T]: A
|
|
90
91
|
},
|
|
91
|
-
...
|
|
92
|
+
...w
|
|
92
93
|
)
|
|
93
94
|
])
|
|
94
|
-
), y = { ...l, ...
|
|
95
|
+
), y = { ...l, ...m };
|
|
95
96
|
return i.set(c, y), y;
|
|
96
97
|
}
|
|
97
98
|
return r && typeof r == "object" ? z(r, {
|
|
@@ -100,9 +101,9 @@ function z(t, a) {
|
|
|
100
101
|
}) : r;
|
|
101
102
|
}
|
|
102
103
|
});
|
|
103
|
-
return s.set(e,
|
|
104
|
+
return s.set(e, h), h;
|
|
104
105
|
}
|
|
105
|
-
function
|
|
106
|
+
function N(t, a) {
|
|
106
107
|
return z(t, {
|
|
107
108
|
...a,
|
|
108
109
|
ssr: a?.ssr ?? !0,
|
|
@@ -114,6 +115,6 @@ function M(t, a) {
|
|
|
114
115
|
});
|
|
115
116
|
}
|
|
116
117
|
export {
|
|
117
|
-
|
|
118
|
-
|
|
118
|
+
M as defineState,
|
|
119
|
+
N as setupStorage
|
|
119
120
|
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use client";"use strict";const h=require("react/jsx-runtime"),r=require("react"),s=require("./utils-0CTNJ4ZE.js"),c=r.createContext({});function S(o){const t=r.useContext(c);return o.verbose&&console.log(`[Store uid]: ${t.uid}`),t}class u{#t;#e;constructor(t){this.uid=Math.random().toString(36).slice(2),this.#t=t??{},this.#e=new Set}subscribe(t){return this.#e.add(t),()=>this.#e.delete(t)}getClientSnapshot(){return this.#t}getServerSnapshot(){return this.#t}get(t){return s.get(this.#t,t)}set(t,e){const n=s.get(this.#t,t),a=s.isTransformer(e)?e(n):e,i={...this.#t};s.set(i,t,a),this.#t=i,this.#e.forEach(l=>l())}}function b(o){const{children:t,value:e}=o,[n]=r.useState(()=>new u(e));return h.jsx(c.Provider,{value:n,children:t})}exports.StateVocabClientProvider=b;exports.VocabStore=u;exports.useStateVocabClientContext=S;
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsx as u } from "react/jsx-runtime";
|
|
3
3
|
import { createContext as h, useContext as l, useState as S } from "react";
|
|
4
|
-
import { g as n,
|
|
4
|
+
import { g as n, i as d, s as b } from "./utils-xV3x3fTc.mjs";
|
|
5
5
|
const i = h({});
|
|
6
|
-
function V(s
|
|
6
|
+
function V(s) {
|
|
7
7
|
const t = l(i);
|
|
8
8
|
return s.verbose && console.log(`[Store uid]: ${t.uid}`), t;
|
|
9
9
|
}
|
package/dist/server.cjs.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const o=require("react/jsx-runtime"),S=require("./constants-CbsduCZ7.js"),d=require("react"),v=require("node:async_hooks"),f=require("./provider-client-B4XQ24JB.js"),b=require("./utils-0CTNJ4ZE.js");function y(e){const t=Object.create(null,{[Symbol.toStringTag]:{value:"Module"}});if(e){for(const r in e)if(r!=="default"){const n=Object.getOwnPropertyDescriptor(e,r);Object.defineProperty(t,r,n.get?n:{enumerable:!0,get:()=>e[r]})}}return t.default=e,Object.freeze(t)}const p=y(v),a=e=>{if(d.useState)throw new Error(`${e} only intended for Server Components`)};let s=null;try{a("StateVocabServerContext"),s=new p.AsyncLocalStorage}catch{s=null}const g=({value:e})=>(s?.enterWith({value:e}),null),P=({children:e})=>e,j=async e=>{a("StateVocabServerContext.Provider");const{value:t,children:r}=e;return o.jsxs(o.Fragment,{children:[o.jsx(g,{value:t}),r]})},h=()=>(a("getStateVocab"),s?.getStore()?.value),x={Provider:s?j:P},V=({value:e,children:t})=>o.jsx(x.Provider,{value:e,children:t});function m(e){const{children:t,value:r={}}=e;return o.jsx(V,{value:r,children:o.jsx(f.StateVocabClientProvider,{value:r,children:t})})}const O="Make sure your component is wrapped in StateVocabProvider";function C(){const e=this[S.STATE_PATH],t=h();if(!t)throw new Error(O);return b.get(t,e)}function E(e){return typeof e=="object"&&e!==null&&"serverSlot"in e}function l(e,t){const r={};for(const n in e){const c=e[n];if(E(c))r[n]=c.serverSlot({getState(...i){return C.apply(this,i)}}),delete r[n].serverSlot,delete r[n].clientSlot;else if(c!==null&&typeof c=="object"){const i=u=>t({[n]:u});r[n]=l(c,i)}else r[n]=c}return r.seed=n=>t(n),r}function k(e){return{...l(e,t=>t),StateVocabProvider({children:t,value:r}){return o.jsx(m,{value:r,children:t})}}}exports.serverify=k;
|
package/dist/server.es.js
CHANGED
|
@@ -1,50 +1,52 @@
|
|
|
1
|
-
import { jsxs as u, Fragment as v, jsx as
|
|
1
|
+
import { jsxs as u, Fragment as v, jsx as c } from "react/jsx-runtime";
|
|
2
|
+
import { S as d } from "./constants-BB1YAX6c.mjs";
|
|
2
3
|
import f from "react";
|
|
3
|
-
import * as
|
|
4
|
-
import { S as
|
|
5
|
-
import {
|
|
4
|
+
import * as p from "node:async_hooks";
|
|
5
|
+
import { S as m } from "./provider-client-C2Aw0Lmi.mjs";
|
|
6
|
+
import { g as b } from "./utils-xV3x3fTc.mjs";
|
|
6
7
|
const i = (e) => {
|
|
7
8
|
if (f.useState)
|
|
8
9
|
throw new Error(`${e} only intended for Server Components`);
|
|
9
10
|
};
|
|
10
|
-
let
|
|
11
|
+
let s = null;
|
|
11
12
|
try {
|
|
12
|
-
i("StateVocabServerContext"),
|
|
13
|
+
i("StateVocabServerContext"), s = new p.AsyncLocalStorage();
|
|
13
14
|
} catch {
|
|
14
|
-
|
|
15
|
+
s = null;
|
|
15
16
|
}
|
|
16
|
-
const
|
|
17
|
+
const h = ({ value: e }) => (s?.enterWith({ value: e }), null), y = ({ children: e }) => e, P = async (e) => {
|
|
17
18
|
i("StateVocabServerContext.Provider");
|
|
18
19
|
const { value: t, children: r } = e;
|
|
19
20
|
return /* @__PURE__ */ u(v, { children: [
|
|
20
|
-
/* @__PURE__ */
|
|
21
|
+
/* @__PURE__ */ c(h, { value: t }),
|
|
21
22
|
r
|
|
22
23
|
] });
|
|
23
|
-
}, g = () => (i("getStateVocab"),
|
|
24
|
-
Provider:
|
|
25
|
-
},
|
|
26
|
-
function
|
|
24
|
+
}, g = () => (i("getStateVocab"), s?.getStore()?.value), V = {
|
|
25
|
+
Provider: s ? P : y
|
|
26
|
+
}, E = ({ value: e, children: t }) => /* @__PURE__ */ c(V.Provider, { value: e, children: t });
|
|
27
|
+
function x(e) {
|
|
27
28
|
const { children: t, value: r = {} } = e;
|
|
28
|
-
return /* @__PURE__ */
|
|
29
|
+
return /* @__PURE__ */ c(E, { value: r, children: /* @__PURE__ */ c(m, { value: r, children: t }) });
|
|
29
30
|
}
|
|
30
|
-
|
|
31
|
-
|
|
31
|
+
const C = "Make sure your component is wrapped in StateVocabProvider";
|
|
32
|
+
function w() {
|
|
33
|
+
const e = this[d], t = g();
|
|
32
34
|
if (!t)
|
|
33
|
-
throw new Error(
|
|
34
|
-
return
|
|
35
|
+
throw new Error(C);
|
|
36
|
+
return b(t, e);
|
|
35
37
|
}
|
|
36
|
-
function
|
|
38
|
+
function R(e) {
|
|
37
39
|
return typeof e == "object" && e !== null && "serverSlot" in e;
|
|
38
40
|
}
|
|
39
41
|
function l(e, t) {
|
|
40
42
|
const r = {};
|
|
41
43
|
for (const o in e) {
|
|
42
44
|
const n = e[o];
|
|
43
|
-
if (
|
|
45
|
+
if (R(n))
|
|
44
46
|
r[o] = n.serverSlot({
|
|
45
47
|
// Slot definition
|
|
46
48
|
getState(...a) {
|
|
47
|
-
return
|
|
49
|
+
return w.apply(this, a);
|
|
48
50
|
}
|
|
49
51
|
}), delete r[o].serverSlot, delete r[o].clientSlot;
|
|
50
52
|
else if (n !== null && typeof n == "object") {
|
|
@@ -53,12 +55,16 @@ function l(e, t) {
|
|
|
53
55
|
} else
|
|
54
56
|
r[o] = n;
|
|
55
57
|
}
|
|
56
|
-
return r.
|
|
58
|
+
return r.seed = (o) => t(o), r;
|
|
57
59
|
}
|
|
58
|
-
function
|
|
59
|
-
return
|
|
60
|
+
function M(e) {
|
|
61
|
+
return {
|
|
62
|
+
...l(e, (t) => t),
|
|
63
|
+
StateVocabProvider({ children: t, value: r }) {
|
|
64
|
+
return /* @__PURE__ */ c(x, { value: r, children: t });
|
|
65
|
+
}
|
|
66
|
+
};
|
|
60
67
|
}
|
|
61
68
|
export {
|
|
62
|
-
|
|
63
|
-
H as serverify
|
|
69
|
+
M as serverify
|
|
64
70
|
};
|
package/dist/types/client.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
export { clientify } from "./setup.client";
|
|
2
|
-
export { StateVocabClientProvider
|
|
2
|
+
export { StateVocabClientProvider } from "./provider.client";
|
|
@@ -3,6 +3,6 @@ export declare const StateVocabClientContext: import("react").Context<VocabStore
|
|
|
3
3
|
/**
|
|
4
4
|
* @see method from from https://zustand.docs.pmnd.rs/learn/guides/nextjs
|
|
5
5
|
*/
|
|
6
|
-
export declare function useStateVocabClientContext(options
|
|
7
|
-
verbose
|
|
6
|
+
export declare function useStateVocabClientContext(options: {
|
|
7
|
+
verbose: boolean;
|
|
8
8
|
}): VocabStore;
|
package/dist/types/server.d.ts
CHANGED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { type DependencyList } from "react";
|
|
2
|
+
import VocabStore from "./store";
|
|
3
|
+
import type { Deserialize, Serialize } from "./state.types";
|
|
4
|
+
export declare function useDebounce<T extends (...args: never[]) => unknown>(effect: T, wait: number | undefined, deps?: DependencyList): (...args: Parameters<T>) => void;
|
|
5
|
+
export declare const sync: <V>(options: {
|
|
6
|
+
vocabStore: VocabStore;
|
|
7
|
+
statePath: string;
|
|
8
|
+
storage: Storage;
|
|
9
|
+
serialize: Serialize<V>;
|
|
10
|
+
deserialize: Deserialize<V>;
|
|
11
|
+
value: V | undefined;
|
|
12
|
+
}) => void;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { PropsWithChildren, ReactNode } from "react";
|
|
1
2
|
import type { Vocab } from "./state.types";
|
|
2
3
|
type Placeholder<V> = {
|
|
3
4
|
getState(): V;
|
|
@@ -9,12 +10,15 @@ type ServerifiedValue<R> = {
|
|
|
9
10
|
[K in keyof R]?: R[K] extends Slot<infer V> ? V : R[K] extends object ? ServerifiedValue<R[K]> : R[K];
|
|
10
11
|
};
|
|
11
12
|
type Serverified<R> = R extends Slot<infer TValue> ? Placeholder<TValue> : R extends object ? {
|
|
12
|
-
|
|
13
|
+
seed(input: ServerifiedValue<R>): Vocab;
|
|
13
14
|
} & {
|
|
14
15
|
[K in keyof R]: Serverified<R[K]>;
|
|
15
16
|
} : R;
|
|
16
17
|
type ServerifyResult<R extends object> = {
|
|
17
|
-
|
|
18
|
+
seed(input: ServerifiedValue<R>): Vocab;
|
|
19
|
+
StateVocabProvider(props: PropsWithChildren<{
|
|
20
|
+
value?: ServerifiedValue<R>;
|
|
21
|
+
}>): Promise<ReactNode>;
|
|
18
22
|
} & {
|
|
19
23
|
[K in keyof R]: Serverified<R[K]>;
|
|
20
24
|
};
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
"use strict";function f(e,s,n){if(!s)return e;const o=s.split(".");let t=e;for(const c of o)if(t!==null&&typeof t=="object"&&c in t)t=t[c];else return n;return t===void 0?n:t}function y(e,s,n){const o=s.replace(/\[(\d+)\]/g,".$1").split(".");let t=e;for(let c=0;c<o.length-1;c++){const r=o[c],i=o[c+1];(t[r]===void 0||t[r]===null)&&(t[r]=/^\d+$/.test(i)?[]:{}),t=t[r]}return t[o[o.length-1]]=n,e}function d(e,s=0){let n;return function(...o){n!==void 0&&clearTimeout(n),n=setTimeout(()=>{n=void 0,e.apply(this,o)},s)}}function a(e){const s=JSON.stringify(e,null,2).split(`
|
|
2
|
+
`),n=[],o=[];for(const t of s){const c=t.match(/^(\s*)"([^"]+)"(\s*:\s*)(.+)$/);if(c){const[,r,i,l,u]=c;n.push(`${r}%c"${i}"%c${l}%c${u}`),o.push("color: #9cdcfe; font-weight: bold","color: #cccccc","color: #ce9178")}else n.push(`%c${t}`),o.push("color: #cccccc")}console.log(n.join(`
|
|
3
|
+
`),...o,e)}const p=e=>typeof e=="function",g=e=>typeof e=="function",h=e=>typeof e<"u",$=e=>g(e)?e():e;exports.debounce=d;exports.get=f;exports.isTransformer=p;exports.isValueDefined=h;exports.logStyled=a;exports.set=y;exports.valueOrFactory=$;
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
function a(t, s, n) {
|
|
2
|
+
if (!s)
|
|
3
|
+
return t;
|
|
4
|
+
const o = s.split(".");
|
|
5
|
+
let e = t;
|
|
6
|
+
for (const c of o)
|
|
7
|
+
if (e !== null && typeof e == "object" && c in e)
|
|
8
|
+
e = e[c];
|
|
9
|
+
else
|
|
10
|
+
return n;
|
|
11
|
+
return e === void 0 ? n : e;
|
|
12
|
+
}
|
|
13
|
+
function y(t, s, n) {
|
|
14
|
+
const o = s.replace(/\[(\d+)\]/g, ".$1").split(".");
|
|
15
|
+
let e = t;
|
|
16
|
+
for (let c = 0; c < o.length - 1; c++) {
|
|
17
|
+
const r = o[c], i = o[c + 1];
|
|
18
|
+
(e[r] === void 0 || e[r] === null) && (e[r] = /^\d+$/.test(i) ? [] : {}), e = e[r];
|
|
19
|
+
}
|
|
20
|
+
return e[o[o.length - 1]] = n, t;
|
|
21
|
+
}
|
|
22
|
+
function d(t, s = 0) {
|
|
23
|
+
let n;
|
|
24
|
+
return function(...o) {
|
|
25
|
+
n !== void 0 && clearTimeout(n), n = setTimeout(() => {
|
|
26
|
+
n = void 0, t.apply(this, o);
|
|
27
|
+
}, s);
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
function p(t) {
|
|
31
|
+
const s = JSON.stringify(t, null, 2).split(`
|
|
32
|
+
`), n = [], o = [];
|
|
33
|
+
for (const e of s) {
|
|
34
|
+
const c = e.match(/^(\s*)"([^"]+)"(\s*:\s*)(.+)$/);
|
|
35
|
+
if (c) {
|
|
36
|
+
const [, r, i, l, u] = c;
|
|
37
|
+
n.push(`${r}%c"${i}"%c${l}%c${u}`), o.push(
|
|
38
|
+
"color: #9cdcfe; font-weight: bold",
|
|
39
|
+
"color: #cccccc",
|
|
40
|
+
"color: #ce9178"
|
|
41
|
+
);
|
|
42
|
+
} else
|
|
43
|
+
n.push(`%c${e}`), o.push("color: #cccccc");
|
|
44
|
+
}
|
|
45
|
+
console.log(n.join(`
|
|
46
|
+
`), ...o, t);
|
|
47
|
+
}
|
|
48
|
+
const g = (t) => typeof t == "function", f = (t) => typeof t == "function", h = (t) => typeof t < "u", $ = (t) => f(t) ? t() : t;
|
|
49
|
+
export {
|
|
50
|
+
h as a,
|
|
51
|
+
d,
|
|
52
|
+
a as g,
|
|
53
|
+
g as i,
|
|
54
|
+
p as l,
|
|
55
|
+
y as s,
|
|
56
|
+
$ as v
|
|
57
|
+
};
|
package/package.json
CHANGED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
"use client";"use strict";const h=require("react/jsx-runtime"),r=require("react"),s=require("./utils-33NqsZoR.js"),c=r.createContext({});function S(o={}){const t=r.useContext(c);return o.verbose&&console.log(`[Store uid]: ${t.uid}`),t}class u{#t;#e;constructor(t){this.uid=Math.random().toString(36).slice(2),this.#t=t??{},this.#e=new Set}subscribe(t){return this.#e.add(t),()=>this.#e.delete(t)}getClientSnapshot(){return this.#t}getServerSnapshot(){return this.#t}get(t){return s.get(this.#t,t)}set(t,e){const n=s.get(this.#t,t),a=s.isTransformer(e)?e(n):e,i={...this.#t};s.set(i,t,a),this.#t=i,this.#e.forEach(l=>l())}}function b(o){const{children:t,value:e}=o,[n]=r.useState(()=>new u(e));return h.jsx(c.Provider,{value:n,children:t})}exports.StateVocabClientProvider=b;exports.VocabStore=u;exports.useStateVocabClientContext=S;
|
package/dist/utils-33NqsZoR.js
DELETED
|
@@ -1,3 +0,0 @@
|
|
|
1
|
-
"use strict";const T=Symbol("state-def"),f=Symbol("state-path"),S=Symbol("state-verbose"),y=Symbol("state-verbose-path"),a=Symbol("state-ssr");function E(t,s,o){if(!s)return t;const n=s.split(".");let e=t;for(const c of n)if(e!==null&&typeof e=="object"&&c in e)e=e[c];else return o;return e===void 0?o:e}function d(t,s,o){const n=s.replace(/\[(\d+)\]/g,".$1").split(".");let e=t;for(let c=0;c<n.length-1;c++){const r=n[c],l=n[c+1];(e[r]===void 0||e[r]===null)&&(e[r]=/^\d+$/.test(l)?[]:{}),e=e[r]}return e[n[n.length-1]]=o,t}function p(t,s=0){let o;return function(...n){o!==void 0&&clearTimeout(o),o=setTimeout(()=>{o=void 0,t.apply(this,n)},s)}}function A(t){const s=JSON.stringify(t,null,2).split(`
|
|
2
|
-
`),o=[],n=[];for(const e of s){const c=e.match(/^(\s*)"([^"]+)"(\s*:\s*)(.+)$/);if(c){const[,r,l,i,u]=c;o.push(`${r}%c"${l}"%c${i}%c${u}`),n.push("color: #9cdcfe; font-weight: bold","color: #cccccc","color: #ce9178")}else o.push(`%c${e}`),n.push("color: #cccccc")}console.log(o.join(`
|
|
3
|
-
`),...n,t)}const m=t=>typeof t=="function",_=t=>typeof t=="function",h=t=>typeof t<"u",g=t=>_(t)?t():t;exports.STATE_DEFINITION=T;exports.STATE_PATH=f;exports.STATE_SSR=a;exports.STATE_VERBOSE=S;exports.STATE_VERBOSE_PATH=y;exports.debounce=p;exports.get=E;exports.isTransformer=m;exports.isValueDefined=h;exports.logStyled=A;exports.set=d;exports.valueOrFactory=g;
|
package/dist/utils-t8tYdd6B.mjs
DELETED
|
@@ -1,63 +0,0 @@
|
|
|
1
|
-
const u = /* @__PURE__ */ Symbol("state-def"), y = /* @__PURE__ */ Symbol("state-path"), S = /* @__PURE__ */ Symbol("state-verbose"), d = /* @__PURE__ */ Symbol("state-verbose-path"), T = /* @__PURE__ */ Symbol("state-ssr");
|
|
2
|
-
function p(t, c, s) {
|
|
3
|
-
if (!c)
|
|
4
|
-
return t;
|
|
5
|
-
const o = c.split(".");
|
|
6
|
-
let e = t;
|
|
7
|
-
for (const n of o)
|
|
8
|
-
if (e !== null && typeof e == "object" && n in e)
|
|
9
|
-
e = e[n];
|
|
10
|
-
else
|
|
11
|
-
return s;
|
|
12
|
-
return e === void 0 ? s : e;
|
|
13
|
-
}
|
|
14
|
-
function h(t, c, s) {
|
|
15
|
-
const o = c.replace(/\[(\d+)\]/g, ".$1").split(".");
|
|
16
|
-
let e = t;
|
|
17
|
-
for (let n = 0; n < o.length - 1; n++) {
|
|
18
|
-
const r = o[n], l = o[n + 1];
|
|
19
|
-
(e[r] === void 0 || e[r] === null) && (e[r] = /^\d+$/.test(l) ? [] : {}), e = e[r];
|
|
20
|
-
}
|
|
21
|
-
return e[o[o.length - 1]] = s, t;
|
|
22
|
-
}
|
|
23
|
-
function m(t, c = 0) {
|
|
24
|
-
let s;
|
|
25
|
-
return function(...o) {
|
|
26
|
-
s !== void 0 && clearTimeout(s), s = setTimeout(() => {
|
|
27
|
-
s = void 0, t.apply(this, o);
|
|
28
|
-
}, c);
|
|
29
|
-
};
|
|
30
|
-
}
|
|
31
|
-
function E(t) {
|
|
32
|
-
const c = JSON.stringify(t, null, 2).split(`
|
|
33
|
-
`), s = [], o = [];
|
|
34
|
-
for (const e of c) {
|
|
35
|
-
const n = e.match(/^(\s*)"([^"]+)"(\s*:\s*)(.+)$/);
|
|
36
|
-
if (n) {
|
|
37
|
-
const [, r, l, i, a] = n;
|
|
38
|
-
s.push(`${r}%c"${l}"%c${i}%c${a}`), o.push(
|
|
39
|
-
"color: #9cdcfe; font-weight: bold",
|
|
40
|
-
"color: #cccccc",
|
|
41
|
-
"color: #ce9178"
|
|
42
|
-
);
|
|
43
|
-
} else
|
|
44
|
-
s.push(`%c${e}`), o.push("color: #cccccc");
|
|
45
|
-
}
|
|
46
|
-
console.log(s.join(`
|
|
47
|
-
`), ...o, t);
|
|
48
|
-
}
|
|
49
|
-
const g = (t) => typeof t == "function", f = (t) => typeof t == "function", v = (t) => typeof t < "u", b = (t) => f(t) ? t() : t;
|
|
50
|
-
export {
|
|
51
|
-
y as S,
|
|
52
|
-
S as a,
|
|
53
|
-
T as b,
|
|
54
|
-
d as c,
|
|
55
|
-
m as d,
|
|
56
|
-
g as e,
|
|
57
|
-
u as f,
|
|
58
|
-
p as g,
|
|
59
|
-
v as i,
|
|
60
|
-
E as l,
|
|
61
|
-
h as s,
|
|
62
|
-
b as v
|
|
63
|
-
};
|