vue-context-storage 0.1.13 → 0.1.15
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 +354 -356
- package/dist/index.d.ts +32 -74
- package/dist/index.js +85 -68
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,356 +1,354 @@
|
|
|
1
|
-
# vue-context-storage
|
|
2
|
-
|
|
3
|
-
Vue 3 context storage system with URL query synchronization support.
|
|
4
|
-
|
|
5
|
-
[](https://www.npmjs.com/package/vue-context-storage)
|
|
6
|
-
[](https://www.typescriptlang.org/)
|
|
7
|
-
[](https://vuejs.org/)
|
|
8
|
-
[](https://bundlephobia.com/package/vue-context-storage)
|
|
9
|
-
[](https://github.com/lviobio/vue-context-storage/issues)
|
|
10
|
-
[](https://github.com/lviobio/vue-context-storage)
|
|
11
|
-
[](https://lviobio.github.io/vue-context-storage/)
|
|
12
|
-
|
|
13
|
-
A powerful state management solution for Vue 3 applications that provides:
|
|
14
|
-
- **Context-based storage** using Vue's provide/inject API
|
|
15
|
-
- **Automatic URL query synchronization** for preserving state across page reloads
|
|
16
|
-
- **Multiple storage contexts** with activation management
|
|
17
|
-
- **Type-safe** TypeScript support
|
|
18
|
-
- **Tree-shakeable** and lightweight
|
|
19
|
-
|
|
20
|
-
## Live Demo
|
|
21
|
-
|
|
22
|
-
🚀 **[Try the interactive playground](https://lviobio.github.io/vue-context-storage)**
|
|
23
|
-
|
|
24
|
-
## Installation
|
|
25
|
-
|
|
26
|
-
```bash
|
|
27
|
-
npm install vue-context-storage
|
|
28
|
-
```
|
|
29
|
-
|
|
30
|
-
## Features
|
|
31
|
-
|
|
32
|
-
- ✅ **Vue 3 Composition API** - Built with modern Vue patterns
|
|
33
|
-
- ✅ **URL Query Sync** - Automatically sync state with URL parameters
|
|
34
|
-
- ✅ **Multiple Contexts** - Support multiple independent storage contexts
|
|
35
|
-
- ✅ **TypeScript** - Full type safety and IntelliSense support
|
|
36
|
-
- ✅ **Flexible** - Works with vue-router 4+
|
|
37
|
-
- ✅ **Transform Helpers** - Built-in utilities for type conversion
|
|
38
|
-
|
|
39
|
-
## Basic Usage
|
|
40
|
-
|
|
41
|
-
### Option 1: Using Vue Plugin (Recommended)
|
|
42
|
-
|
|
43
|
-
Register the plugin in your main app file:
|
|
44
|
-
|
|
45
|
-
```typescript
|
|
46
|
-
import { createApp } from 'vue'
|
|
47
|
-
import { VueContextStoragePlugin } from 'vue-context-storage/plugin'
|
|
48
|
-
import App from './App.vue'
|
|
49
|
-
|
|
50
|
-
const app = createApp(App)
|
|
51
|
-
|
|
52
|
-
// Register components globally
|
|
53
|
-
app.use(VueContextStoragePlugin)
|
|
54
|
-
|
|
55
|
-
app.mount('#app')
|
|
56
|
-
```
|
|
57
|
-
|
|
58
|
-
Then use components without importing in your `App.vue`:
|
|
59
|
-
|
|
60
|
-
```vue
|
|
61
|
-
<template>
|
|
62
|
-
<ContextStorage>
|
|
63
|
-
<router-view />
|
|
64
|
-
</ContextStorage>
|
|
65
|
-
</template>
|
|
66
|
-
```
|
|
67
|
-
|
|
68
|
-
### Option 2: Manual Component Import
|
|
69
|
-
|
|
70
|
-
Import components individually when needed in your `App.vue`:
|
|
71
|
-
|
|
72
|
-
```vue
|
|
73
|
-
<template>
|
|
74
|
-
<ContextStorage>
|
|
75
|
-
<router-view />
|
|
76
|
-
</ContextStorage>
|
|
77
|
-
</template>
|
|
78
|
-
|
|
79
|
-
<script setup lang="ts">
|
|
80
|
-
import { ContextStorage } from 'vue-context-storage/components'
|
|
81
|
-
</script>
|
|
82
|
-
```
|
|
83
|
-
|
|
84
|
-
## Use Query Handler in Components
|
|
85
|
-
|
|
86
|
-
Sync reactive state with URL query parameters:
|
|
87
|
-
|
|
88
|
-
```vue
|
|
89
|
-
<script setup lang="ts">
|
|
90
|
-
import { ref } from 'vue'
|
|
91
|
-
import { useContextStorageQueryHandler } from 'vue-context-storage'
|
|
92
|
-
|
|
93
|
-
interface Filters {
|
|
94
|
-
search: string
|
|
95
|
-
status: string
|
|
96
|
-
page: number
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
const filters = reactive<Filters>({
|
|
100
|
-
search: '',
|
|
101
|
-
status: 'active',
|
|
102
|
-
page: 1,
|
|
103
|
-
})
|
|
104
|
-
|
|
105
|
-
// Automatically syncs filters with URL query
|
|
106
|
-
useContextStorageQueryHandler(filters, {
|
|
107
|
-
prefix: 'filters', // URL will be: ?filters[search]=...&filters[status]=...
|
|
108
|
-
})
|
|
109
|
-
</script>
|
|
110
|
-
```
|
|
111
|
-
|
|
112
|
-
## Advanced Usage
|
|
113
|
-
|
|
114
|
-
### Using Transform Helpers
|
|
115
|
-
|
|
116
|
-
Convert URL query string values to proper types:
|
|
117
|
-
|
|
118
|
-
```typescript
|
|
119
|
-
import { ref } from 'vue'
|
|
120
|
-
import { useContextStorageQueryHandler, asNumber, asString } from 'vue-context-storage'
|
|
121
|
-
|
|
122
|
-
interface TableState {
|
|
123
|
-
page: number
|
|
124
|
-
search: string
|
|
125
|
-
perPage: number
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
const state = ref<TableState>({
|
|
129
|
-
page: 1,
|
|
130
|
-
search: '',
|
|
131
|
-
perPage: 25,
|
|
132
|
-
})
|
|
133
|
-
|
|
134
|
-
useContextStorageQueryHandler(state, {
|
|
135
|
-
prefix: 'table',
|
|
136
|
-
transform: (deserialized, initial) => ({
|
|
137
|
-
page: asNumber(deserialized.page, { fallback: 1 }),
|
|
138
|
-
search: asString(deserialized.search, { fallback: '' }),
|
|
139
|
-
perPage: asNumber(deserialized.perPage, { fallback: 25 }),
|
|
140
|
-
}),
|
|
141
|
-
})
|
|
142
|
-
```
|
|
143
|
-
|
|
144
|
-
### Available Transform Helpers
|
|
145
|
-
|
|
146
|
-
- `asNumber(value, options)` - Convert to number
|
|
147
|
-
- `asString(value, options)` - Convert to string
|
|
148
|
-
- `asBoolean(value, options)` - Convert to boolean
|
|
149
|
-
- `asArray(value, options)` - Convert to array
|
|
150
|
-
- `asNumberArray(value, options)` - Convert to number array
|
|
151
|
-
|
|
152
|
-
### Using Zod Schemas
|
|
153
|
-
|
|
154
|
-
Alternatively, you can use [Zod](https://zod.dev/) schemas for automatic validation and type inference:
|
|
155
|
-
|
|
156
|
-
```typescript
|
|
157
|
-
import { z } from 'zod'
|
|
158
|
-
import { useContextStorageQueryHandler } from 'vue-context-storage'
|
|
159
|
-
|
|
160
|
-
// Define schema with automatic coercion
|
|
161
|
-
const FiltersSchema = z.object({
|
|
162
|
-
search: z.string().default(''),
|
|
163
|
-
page: z.coerce.number().int().positive().default(1),
|
|
164
|
-
status: z.enum(['active', 'inactive']).default('active'),
|
|
165
|
-
})
|
|
166
|
-
|
|
167
|
-
const filters = ref(FiltersSchema.parse({}))
|
|
168
|
-
|
|
169
|
-
// Use schema for automatic validation
|
|
170
|
-
useContextStorageQueryHandler(filters, {
|
|
171
|
-
prefix: 'filters',
|
|
172
|
-
schema: FiltersSchema,
|
|
173
|
-
})
|
|
174
|
-
```
|
|
175
|
-
|
|
176
|
-
**Benefits:**
|
|
177
|
-
- Automatic type coercion (strings → numbers, etc.)
|
|
178
|
-
- Runtime validation with detailed errors
|
|
179
|
-
- Automatic TypeScript type inference
|
|
180
|
-
- Less boilerplate code
|
|
181
|
-
- Single source of truth for structure and validation
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
- `
|
|
222
|
-
- `
|
|
223
|
-
- `
|
|
224
|
-
- `
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
- `
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
- `
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
Contributions are welcome! Please feel free to submit a Pull Request.
|
|
1
|
+
# vue-context-storage
|
|
2
|
+
|
|
3
|
+
Vue 3 context storage system with URL query synchronization support.
|
|
4
|
+
|
|
5
|
+
[](https://www.npmjs.com/package/vue-context-storage)
|
|
6
|
+
[](https://www.typescriptlang.org/)
|
|
7
|
+
[](https://vuejs.org/)
|
|
8
|
+
[](https://bundlephobia.com/package/vue-context-storage)
|
|
9
|
+
[](https://github.com/lviobio/vue-context-storage/issues)
|
|
10
|
+
[](https://github.com/lviobio/vue-context-storage)
|
|
11
|
+
[](https://lviobio.github.io/vue-context-storage/)
|
|
12
|
+
|
|
13
|
+
A powerful state management solution for Vue 3 applications that provides:
|
|
14
|
+
- **Context-based storage** using Vue's provide/inject API
|
|
15
|
+
- **Automatic URL query synchronization** for preserving state across page reloads
|
|
16
|
+
- **Multiple storage contexts** with activation management
|
|
17
|
+
- **Type-safe** TypeScript support
|
|
18
|
+
- **Tree-shakeable** and lightweight
|
|
19
|
+
|
|
20
|
+
## Live Demo
|
|
21
|
+
|
|
22
|
+
🚀 **[Try the interactive playground](https://lviobio.github.io/vue-context-storage)**
|
|
23
|
+
|
|
24
|
+
## Installation
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
npm install vue-context-storage
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## Features
|
|
31
|
+
|
|
32
|
+
- ✅ **Vue 3 Composition API** - Built with modern Vue patterns
|
|
33
|
+
- ✅ **URL Query Sync** - Automatically sync state with URL parameters
|
|
34
|
+
- ✅ **Multiple Contexts** - Support multiple independent storage contexts
|
|
35
|
+
- ✅ **TypeScript** - Full type safety and IntelliSense support
|
|
36
|
+
- ✅ **Flexible** - Works with vue-router 4+
|
|
37
|
+
- ✅ **Transform Helpers** - Built-in utilities for type conversion
|
|
38
|
+
|
|
39
|
+
## Basic Usage
|
|
40
|
+
|
|
41
|
+
### Option 1: Using Vue Plugin (Recommended)
|
|
42
|
+
|
|
43
|
+
Register the plugin in your main app file:
|
|
44
|
+
|
|
45
|
+
```typescript
|
|
46
|
+
import { createApp } from 'vue'
|
|
47
|
+
import { VueContextStoragePlugin } from 'vue-context-storage/plugin'
|
|
48
|
+
import App from './App.vue'
|
|
49
|
+
|
|
50
|
+
const app = createApp(App)
|
|
51
|
+
|
|
52
|
+
// Register components globally
|
|
53
|
+
app.use(VueContextStoragePlugin)
|
|
54
|
+
|
|
55
|
+
app.mount('#app')
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
Then use components without importing in your `App.vue`:
|
|
59
|
+
|
|
60
|
+
```vue
|
|
61
|
+
<template>
|
|
62
|
+
<ContextStorage>
|
|
63
|
+
<router-view />
|
|
64
|
+
</ContextStorage>
|
|
65
|
+
</template>
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
### Option 2: Manual Component Import
|
|
69
|
+
|
|
70
|
+
Import components individually when needed in your `App.vue`:
|
|
71
|
+
|
|
72
|
+
```vue
|
|
73
|
+
<template>
|
|
74
|
+
<ContextStorage>
|
|
75
|
+
<router-view />
|
|
76
|
+
</ContextStorage>
|
|
77
|
+
</template>
|
|
78
|
+
|
|
79
|
+
<script setup lang="ts">
|
|
80
|
+
import { ContextStorage } from 'vue-context-storage/components'
|
|
81
|
+
</script>
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
## Use Query Handler in Components
|
|
85
|
+
|
|
86
|
+
Sync reactive state with URL query parameters:
|
|
87
|
+
|
|
88
|
+
```vue
|
|
89
|
+
<script setup lang="ts">
|
|
90
|
+
import { ref } from 'vue'
|
|
91
|
+
import { useContextStorageQueryHandler } from 'vue-context-storage'
|
|
92
|
+
|
|
93
|
+
interface Filters {
|
|
94
|
+
search: string
|
|
95
|
+
status: string
|
|
96
|
+
page: number
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
const filters = reactive<Filters>({
|
|
100
|
+
search: '',
|
|
101
|
+
status: 'active',
|
|
102
|
+
page: 1,
|
|
103
|
+
})
|
|
104
|
+
|
|
105
|
+
// Automatically syncs filters with URL query
|
|
106
|
+
useContextStorageQueryHandler(filters, {
|
|
107
|
+
prefix: 'filters', // URL will be: ?filters[search]=...&filters[status]=...
|
|
108
|
+
})
|
|
109
|
+
</script>
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
## Advanced Usage
|
|
113
|
+
|
|
114
|
+
### Using Transform Helpers
|
|
115
|
+
|
|
116
|
+
Convert URL query string values to proper types:
|
|
117
|
+
|
|
118
|
+
```typescript
|
|
119
|
+
import { ref } from 'vue'
|
|
120
|
+
import { useContextStorageQueryHandler, asNumber, asString } from 'vue-context-storage'
|
|
121
|
+
|
|
122
|
+
interface TableState {
|
|
123
|
+
page: number
|
|
124
|
+
search: string
|
|
125
|
+
perPage: number
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
const state = ref<TableState>({
|
|
129
|
+
page: 1,
|
|
130
|
+
search: '',
|
|
131
|
+
perPage: 25,
|
|
132
|
+
})
|
|
133
|
+
|
|
134
|
+
useContextStorageQueryHandler(state, {
|
|
135
|
+
prefix: 'table',
|
|
136
|
+
transform: (deserialized, initial) => ({
|
|
137
|
+
page: asNumber(deserialized.page, { fallback: 1 }),
|
|
138
|
+
search: asString(deserialized.search, { fallback: '' }),
|
|
139
|
+
perPage: asNumber(deserialized.perPage, { fallback: 25 }),
|
|
140
|
+
}),
|
|
141
|
+
})
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
### Available Transform Helpers
|
|
145
|
+
|
|
146
|
+
- `asNumber(value, options)` - Convert to number
|
|
147
|
+
- `asString(value, options)` - Convert to string
|
|
148
|
+
- `asBoolean(value, options)` - Convert to boolean
|
|
149
|
+
- `asArray(value, options)` - Convert to array
|
|
150
|
+
- `asNumberArray(value, options)` - Convert to number array
|
|
151
|
+
|
|
152
|
+
### Using Zod Schemas
|
|
153
|
+
|
|
154
|
+
Alternatively, you can use [Zod](https://zod.dev/) schemas for automatic validation and type inference:
|
|
155
|
+
|
|
156
|
+
```typescript
|
|
157
|
+
import { z } from 'zod'
|
|
158
|
+
import { useContextStorageQueryHandler } from 'vue-context-storage'
|
|
159
|
+
|
|
160
|
+
// Define schema with automatic coercion
|
|
161
|
+
const FiltersSchema = z.object({
|
|
162
|
+
search: z.string().default(''),
|
|
163
|
+
page: z.coerce.number().int().positive().default(1),
|
|
164
|
+
status: z.enum(['active', 'inactive']).default('active'),
|
|
165
|
+
})
|
|
166
|
+
|
|
167
|
+
const filters = ref(FiltersSchema.parse({}))
|
|
168
|
+
|
|
169
|
+
// Use schema for automatic validation
|
|
170
|
+
useContextStorageQueryHandler(filters, {
|
|
171
|
+
prefix: 'filters',
|
|
172
|
+
schema: FiltersSchema,
|
|
173
|
+
})
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
**Benefits:**
|
|
177
|
+
- Automatic type coercion (strings → numbers, etc.)
|
|
178
|
+
- Runtime validation with detailed errors
|
|
179
|
+
- Automatic TypeScript type inference
|
|
180
|
+
- Less boilerplate code
|
|
181
|
+
- Single source of truth for structure and validation
|
|
182
|
+
|
|
183
|
+
### Preserve Empty State
|
|
184
|
+
|
|
185
|
+
Keep empty state in URL to prevent resetting on reload:
|
|
186
|
+
|
|
187
|
+
```typescript
|
|
188
|
+
useContextStorageQueryHandler(filters, {
|
|
189
|
+
prefix: 'filters',
|
|
190
|
+
preserveEmptyState: true,
|
|
191
|
+
// Empty filters will show as: ?filters
|
|
192
|
+
// Without this option, empty filters would clear the URL completely
|
|
193
|
+
})
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
### Configure Query Handler
|
|
197
|
+
|
|
198
|
+
Customize global behavior:
|
|
199
|
+
|
|
200
|
+
```typescript
|
|
201
|
+
import { ContextStorageQueryHandler } from 'vue-context-storage'
|
|
202
|
+
|
|
203
|
+
ContextStorageQueryHandler.configure({
|
|
204
|
+
mode: 'push', // 'replace' (default) or 'push' for history
|
|
205
|
+
preserveUnusedKeys: true, // Keep other query params
|
|
206
|
+
preserveEmptyState: false,
|
|
207
|
+
})
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
## API Reference
|
|
211
|
+
|
|
212
|
+
### Composables
|
|
213
|
+
|
|
214
|
+
#### `useContextStorageQueryHandler<T>(data, options)`
|
|
215
|
+
|
|
216
|
+
Registers reactive data for URL query synchronization.
|
|
217
|
+
|
|
218
|
+
**Parameters:**
|
|
219
|
+
- `data: MaybeRefOrGetter<T>` - Reactive reference to sync
|
|
220
|
+
- `options?: RegisterQueryHandlerOptions<T>`
|
|
221
|
+
- `prefix?: string` - Query parameter prefix
|
|
222
|
+
- `transform?: (deserialized, initial) => T` - Transform function
|
|
223
|
+
- `preserveEmptyState?: boolean` - Keep empty state in URL
|
|
224
|
+
- `mergeOnlyExistingKeysWithoutTransform?: boolean` - Only merge existing keys (default: true)
|
|
225
|
+
|
|
226
|
+
### Classes
|
|
227
|
+
|
|
228
|
+
#### `ContextStorageQueryHandler`
|
|
229
|
+
|
|
230
|
+
Main handler for URL query synchronization.
|
|
231
|
+
|
|
232
|
+
**Static Methods:**
|
|
233
|
+
- `configure(options): ContextStorageHandlerConstructor` - Configure global options
|
|
234
|
+
- `getInitialStateResolver(): () => LocationQuery` - Get initial state resolver
|
|
235
|
+
|
|
236
|
+
**Methods:**
|
|
237
|
+
- `register<T>(data, options): () => void` - Register data for sync
|
|
238
|
+
- `setEnabled(state, initial): void` - Enable/disable handler
|
|
239
|
+
- `setInitialState(state): void` - Set initial state
|
|
240
|
+
|
|
241
|
+
### Transform Helpers
|
|
242
|
+
|
|
243
|
+
All transform helpers support nullable and missable options:
|
|
244
|
+
|
|
245
|
+
```typescript
|
|
246
|
+
asNumber(value, {
|
|
247
|
+
fallback: 0, // Default value
|
|
248
|
+
nullable: false, // Allow null return
|
|
249
|
+
missable: false, // Allow undefined return
|
|
250
|
+
})
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
## TypeScript Support
|
|
254
|
+
|
|
255
|
+
Full TypeScript support with type inference:
|
|
256
|
+
|
|
257
|
+
```typescript
|
|
258
|
+
import type {
|
|
259
|
+
ContextStorageHandler,
|
|
260
|
+
ContextStorageHandlerConstructor,
|
|
261
|
+
IContextStorageQueryHandler,
|
|
262
|
+
QueryValue,
|
|
263
|
+
SerializeOptions,
|
|
264
|
+
} from 'vue-context-storage'
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
When using Zod schemas, TypeScript will automatically infer types:
|
|
268
|
+
|
|
269
|
+
```typescript
|
|
270
|
+
const FiltersSchema = z.object({
|
|
271
|
+
search: z.string().default(''),
|
|
272
|
+
page: z.coerce.number().default(1),
|
|
273
|
+
})
|
|
274
|
+
|
|
275
|
+
type Filters = z.infer<typeof FiltersSchema>
|
|
276
|
+
// Result: { search: string; page: number }
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
## Examples
|
|
280
|
+
|
|
281
|
+
### Pagination with URL Sync
|
|
282
|
+
|
|
283
|
+
```typescript
|
|
284
|
+
import { ref } from 'vue'
|
|
285
|
+
import { useContextStorageQueryHandler, asNumber } from 'vue-context-storage'
|
|
286
|
+
|
|
287
|
+
const pagination = ref({
|
|
288
|
+
page: 1,
|
|
289
|
+
perPage: 25,
|
|
290
|
+
total: 0,
|
|
291
|
+
})
|
|
292
|
+
|
|
293
|
+
useContextStorageQueryHandler(pagination, {
|
|
294
|
+
prefix: 'page',
|
|
295
|
+
transform: (data, initial) => ({
|
|
296
|
+
page: asNumber(data.page, { fallback: 1 }),
|
|
297
|
+
perPage: asNumber(data.perPage, { fallback: 25 }),
|
|
298
|
+
total: initial.total, // Don't sync total from URL
|
|
299
|
+
})
|
|
300
|
+
})
|
|
301
|
+
```
|
|
302
|
+
|
|
303
|
+
## Peer Dependencies
|
|
304
|
+
|
|
305
|
+
- `vue`: ^3.5.0
|
|
306
|
+
- `vue-router`: ^4.0.0
|
|
307
|
+
- `zod`: ^4.0.0 (optional - only if using schema validation)
|
|
308
|
+
|
|
309
|
+
## License
|
|
310
|
+
|
|
311
|
+
MIT
|
|
312
|
+
|
|
313
|
+
## Development
|
|
314
|
+
|
|
315
|
+
### Running Playground Locally
|
|
316
|
+
|
|
317
|
+
```bash
|
|
318
|
+
# Development mode (hot reload)
|
|
319
|
+
npm run play
|
|
320
|
+
|
|
321
|
+
# Production preview
|
|
322
|
+
npm run build:playground
|
|
323
|
+
npm run preview:playground
|
|
324
|
+
```
|
|
325
|
+
|
|
326
|
+
### Building
|
|
327
|
+
|
|
328
|
+
```bash
|
|
329
|
+
# Build library
|
|
330
|
+
npm run build
|
|
331
|
+
|
|
332
|
+
# Build playground for deployment
|
|
333
|
+
npm run build:playground
|
|
334
|
+
```
|
|
335
|
+
|
|
336
|
+
### Testing & Quality
|
|
337
|
+
|
|
338
|
+
```bash
|
|
339
|
+
# Run all checks
|
|
340
|
+
npm run check
|
|
341
|
+
|
|
342
|
+
# Type checking
|
|
343
|
+
npm run ts:check
|
|
344
|
+
|
|
345
|
+
# Linting
|
|
346
|
+
npm run lint
|
|
347
|
+
|
|
348
|
+
# Formatting
|
|
349
|
+
npm run format
|
|
350
|
+
```
|
|
351
|
+
|
|
352
|
+
## Contributing
|
|
353
|
+
|
|
354
|
+
Contributions are welcome! Please feel free to submit a Pull Request.
|
package/dist/index.d.ts
CHANGED
|
@@ -62,9 +62,9 @@ declare const __VLS_export$1: vue9.DefineComponent<vue9.ExtractPropTypes<{
|
|
|
62
62
|
interface Props {
|
|
63
63
|
handlers?: ContextStorageHandlerConstructor[];
|
|
64
64
|
}
|
|
65
|
-
declare var
|
|
65
|
+
declare var __VLS_14: {};
|
|
66
66
|
type __VLS_Slots = {} & {
|
|
67
|
-
default?: (props: typeof
|
|
67
|
+
default?: (props: typeof __VLS_14) => any;
|
|
68
68
|
};
|
|
69
69
|
declare const __VLS_base: vue9.DefineComponent<Props, {}, {}, {}, {}, vue9.ComponentOptionsMixin, vue9.ComponentOptionsMixin, {}, string, vue9.PublicProps, Readonly<Props> & Readonly<{}>, {}, {}, {}, {}, string, vue9.ComponentProvideOptions, false, {}, any>;
|
|
70
70
|
declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
|
|
@@ -78,6 +78,32 @@ type __VLS_WithSlots<T, S> = T & {
|
|
|
78
78
|
//#region src/plugin.d.ts
|
|
79
79
|
declare const VueContextStoragePlugin: Plugin;
|
|
80
80
|
//#endregion
|
|
81
|
+
//#region src/collection.d.ts
|
|
82
|
+
type CollectionManagerItem = {
|
|
83
|
+
key: string;
|
|
84
|
+
handlers: ContextStorageHandler[];
|
|
85
|
+
};
|
|
86
|
+
interface ItemOptions {
|
|
87
|
+
key: string;
|
|
88
|
+
}
|
|
89
|
+
declare class CollectionManager {
|
|
90
|
+
private handlerConstructors;
|
|
91
|
+
active?: CollectionManagerItem;
|
|
92
|
+
private collection;
|
|
93
|
+
private onActiveChangeCallbacks;
|
|
94
|
+
private readonly isReadyPromise;
|
|
95
|
+
private resolveMarkAsReady;
|
|
96
|
+
constructor(handlerConstructors: ContextStorageHandlerConstructor[]);
|
|
97
|
+
isReady(): Promise<void>;
|
|
98
|
+
markAsReady(): void;
|
|
99
|
+
onActiveChange(callback: (item: CollectionManagerItem) => void): void;
|
|
100
|
+
first(): CollectionManagerItem | undefined;
|
|
101
|
+
findItemByKey(key: string): CollectionManagerItem | undefined;
|
|
102
|
+
add(options: ItemOptions): CollectionManagerItem;
|
|
103
|
+
remove(removeItem: CollectionManagerItem): void;
|
|
104
|
+
setActive(activeItem: CollectionManagerItem): void;
|
|
105
|
+
}
|
|
106
|
+
//#endregion
|
|
81
107
|
//#region src/symbols.d.ts
|
|
82
108
|
declare const collection: unique symbol;
|
|
83
109
|
declare const collectionItem: unique symbol;
|
|
@@ -247,52 +273,6 @@ declare class ContextStorageQueryHandler implements IContextStorageQueryHandler
|
|
|
247
273
|
register<T extends Record<string, unknown>>(data: MaybeRefOrGetter<T>, options: RegisterQueryHandlerOptions<T>): () => void;
|
|
248
274
|
}
|
|
249
275
|
//#endregion
|
|
250
|
-
//#region src/handlers/query/helpers.d.ts
|
|
251
|
-
interface SerializeOptions {
|
|
252
|
-
/**
|
|
253
|
-
* Custom prefix for serialized keys.
|
|
254
|
-
* @example
|
|
255
|
-
* - prefix: 'filters' => 'filters[key]'
|
|
256
|
-
* - prefix: 'search' => 'search[key]'
|
|
257
|
-
* - prefix: '' => 'key' (no prefix)
|
|
258
|
-
*/
|
|
259
|
-
prefix?: string;
|
|
260
|
-
}
|
|
261
|
-
/**
|
|
262
|
-
* Serializes filter parameters into a URL-friendly format.
|
|
263
|
-
*
|
|
264
|
-
* @param params - Raw parameters object to serialize
|
|
265
|
-
* @param options - Serialization options
|
|
266
|
-
* @returns Serialized parameters with prefixed keys
|
|
267
|
-
*
|
|
268
|
-
* @example
|
|
269
|
-
* // With default prefix 'filters'
|
|
270
|
-
* serializeFiltersParams({ status: 'active', tags: ['a', 'b'] })
|
|
271
|
-
* // => { 'filters[status]': 'active', 'filters[tags]': 'a,b' }
|
|
272
|
-
*
|
|
273
|
-
* @example
|
|
274
|
-
* // With custom prefix
|
|
275
|
-
* serializeFiltersParams({ name: 'John', all: true }, { prefix: 'search' })
|
|
276
|
-
* // => { 'search[name]': 'John', 'search[all]': '1' }
|
|
277
|
-
*
|
|
278
|
-
* @example
|
|
279
|
-
* // Without prefix
|
|
280
|
-
* serializeFiltersParams({ page: 1, all: false }, { prefix: '' })
|
|
281
|
-
* // => { 'page': '1', 'all': '0' }
|
|
282
|
-
*/
|
|
283
|
-
declare function serializeParams(params: Record<string, unknown>, options?: SerializeOptions): LocationQuery;
|
|
284
|
-
/**
|
|
285
|
-
* Deserializes query parameters from a URL-friendly format back to an object.
|
|
286
|
-
*
|
|
287
|
-
* @param params - Serialized parameters object
|
|
288
|
-
* @returns Deserialized parameters object
|
|
289
|
-
*
|
|
290
|
-
* @example
|
|
291
|
-
* deserializeParams({ 'filters[status]': 'active', search: 'test' })
|
|
292
|
-
* // => { filters: {status: 'active'}, search: 'test' }
|
|
293
|
-
*/
|
|
294
|
-
declare function deserializeParams(params: Record<string, any>): Record<string, any>;
|
|
295
|
-
//#endregion
|
|
296
276
|
//#region src/handlers/query/transform-helpers.d.ts
|
|
297
277
|
declare function asNumber(value: QueryValue | number | undefined): number;
|
|
298
278
|
declare function asNumber(value: QueryValue | number | undefined, options: {
|
|
@@ -417,35 +397,13 @@ declare const transform: {
|
|
|
417
397
|
asBoolean: typeof asBoolean;
|
|
418
398
|
};
|
|
419
399
|
//#endregion
|
|
420
|
-
//#region src/collection.d.ts
|
|
421
|
-
type ContextStorageCollectionItem = {
|
|
422
|
-
key: string;
|
|
423
|
-
handlers: ContextStorageHandler[];
|
|
424
|
-
};
|
|
425
|
-
interface ItemOptions {
|
|
426
|
-
key: string;
|
|
427
|
-
}
|
|
428
|
-
declare class ContextStorageCollection {
|
|
429
|
-
private handlerConstructors;
|
|
430
|
-
active?: ContextStorageCollectionItem;
|
|
431
|
-
private collection;
|
|
432
|
-
private onActiveChangeCallbacks;
|
|
433
|
-
constructor(handlerConstructors: ContextStorageHandlerConstructor[]);
|
|
434
|
-
onActiveChange(callback: (item: ContextStorageCollectionItem) => void): void;
|
|
435
|
-
first(): ContextStorageCollectionItem | undefined;
|
|
436
|
-
findItemByKey(key: string): ContextStorageCollectionItem | undefined;
|
|
437
|
-
add(options: ItemOptions): ContextStorageCollectionItem;
|
|
438
|
-
remove(removeItem: ContextStorageCollectionItem): void;
|
|
439
|
-
setActive(activeItem: ContextStorageCollectionItem): void;
|
|
440
|
-
}
|
|
441
|
-
//#endregion
|
|
442
400
|
//#region src/injectionSymbols.d.ts
|
|
443
|
-
declare const contextStorageCollectionInjectKey: InjectionKey<
|
|
444
|
-
declare const contextStorageCollectionItemInjectKey: InjectionKey<
|
|
445
|
-
declare const contextStorageHandlersInjectKey: InjectionKey<
|
|
401
|
+
declare const contextStorageCollectionInjectKey: InjectionKey<CollectionManager>;
|
|
402
|
+
declare const contextStorageCollectionItemInjectKey: InjectionKey<CollectionManagerItem>;
|
|
403
|
+
declare const contextStorageHandlersInjectKey: InjectionKey<CollectionManagerItem['handlers']>;
|
|
446
404
|
declare const contextStorageQueryHandlerInjectKey: InjectionKey<InstanceType<typeof ContextStorageQueryHandler>>;
|
|
447
405
|
//#endregion
|
|
448
406
|
//#region src/constants.d.ts
|
|
449
407
|
declare const defaultHandlers: ContextStorageHandlerConstructor[];
|
|
450
408
|
//#endregion
|
|
451
|
-
export { _default as ContextStorage, _default$1 as ContextStorageActivator, _default$2 as ContextStorageCollection, type ContextStorageHandler, type ContextStorageHandlerConstructor, _default$3 as ContextStorageProvider, ContextStorageQueryHandler, type IContextStorageQueryHandler, type QueryValue, type RegisterBaseOptions,
|
|
409
|
+
export { CollectionManager, type CollectionManagerItem, _default as ContextStorage, _default$1 as ContextStorageActivator, _default$2 as ContextStorageCollection, type ContextStorageHandler, type ContextStorageHandlerConstructor, _default$3 as ContextStorageProvider, ContextStorageQueryHandler, type IContextStorageQueryHandler, type QueryValue, type RegisterBaseOptions, VueContextStoragePlugin, asArray, asBoolean, asNumber, asNumberArray, asString, collection, collectionItem, contextStorageCollectionInjectKey, contextStorageCollectionItemInjectKey, contextStorageHandlersInjectKey, contextStorageQueryHandler, contextStorageQueryHandlerInjectKey, defaultHandlers, handlers, transform, useContextStorageQueryHandler };
|
package/dist/index.js
CHANGED
|
@@ -1,14 +1,25 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { createBlock, createVNode, defineComponent, getCurrentInstance, h, inject, onBeforeUnmount, onUnmounted, openBlock, provide, renderSlot, toValue, watch, withCtx } from "vue";
|
|
2
2
|
import { cloneDeep, isEqual, merge, pick } from "lodash";
|
|
3
3
|
import { useRoute, useRouter } from "vue-router";
|
|
4
4
|
|
|
5
5
|
//#region src/collection.ts
|
|
6
|
-
var
|
|
6
|
+
var CollectionManager = class {
|
|
7
7
|
active = void 0;
|
|
8
8
|
collection = [];
|
|
9
9
|
onActiveChangeCallbacks = [];
|
|
10
|
+
isReadyPromise;
|
|
11
|
+
resolveMarkAsReady = void 0;
|
|
10
12
|
constructor(handlerConstructors) {
|
|
11
13
|
this.handlerConstructors = handlerConstructors;
|
|
14
|
+
this.isReadyPromise = new Promise((resolve) => {
|
|
15
|
+
this.resolveMarkAsReady = resolve;
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
isReady() {
|
|
19
|
+
return this.isReadyPromise;
|
|
20
|
+
}
|
|
21
|
+
markAsReady() {
|
|
22
|
+
this.resolveMarkAsReady?.();
|
|
12
23
|
}
|
|
13
24
|
onActiveChange(callback) {
|
|
14
25
|
this.onActiveChangeCallbacks.push(callback);
|
|
@@ -28,7 +39,7 @@ var ContextStorageCollection = class {
|
|
|
28
39
|
return item;
|
|
29
40
|
}
|
|
30
41
|
remove(removeItem) {
|
|
31
|
-
if (this.collection.indexOf(removeItem) === -1) throw new Error("[
|
|
42
|
+
if (this.collection.indexOf(removeItem) === -1) throw new Error("[vue-context-storage] Item not found in collection");
|
|
32
43
|
this.collection = this.collection.filter((item) => item !== removeItem);
|
|
33
44
|
if (this.active === removeItem && this.collection.length > 0) this.setActive(this.collection[this.collection.length - 1]);
|
|
34
45
|
}
|
|
@@ -130,7 +141,7 @@ const contextStorageQueryHandler = Symbol("context-storage-query-handler");
|
|
|
130
141
|
//#region src/handlers/query/index.ts
|
|
131
142
|
function useContextStorageQueryHandler(data, options) {
|
|
132
143
|
const handler = inject(contextStorageQueryHandler);
|
|
133
|
-
if (!handler) throw new Error("[
|
|
144
|
+
if (!handler) throw new Error("[vue-context-storage] ContextStorageQueryHandler is not provided");
|
|
134
145
|
const uid = getCurrentInstance()?.uid || 0;
|
|
135
146
|
const causer = (/* @__PURE__ */ new Error()).stack?.split("\n")[2]?.trimStart() || "unknown";
|
|
136
147
|
const stop = handler.register(data, {
|
|
@@ -272,9 +283,7 @@ var ContextStorageQueryHandler = class ContextStorageQueryHandler {
|
|
|
272
283
|
if (deserializedKeys.length === 1 && deserialized[this.options.emptyPlaceholder] === null) delete deserialized[this.options.emptyPlaceholder];
|
|
273
284
|
}
|
|
274
285
|
if (item.options?.schema) {
|
|
275
|
-
console.log("[vue-context-storage] 248", deserialized);
|
|
276
286
|
const result = item.options.schema.safeParse(deserialized);
|
|
277
|
-
console.log("[vue-context-storage] 251", result);
|
|
278
287
|
if (result.success) deserialized = result.data;
|
|
279
288
|
else console.warn("[vue-context-storage] schema parse failed", result.error);
|
|
280
289
|
if (item.options?.transform) console.warn("[vue-context-storage] transform is not supported with schema");
|
|
@@ -348,14 +357,18 @@ const contextStorageHandlersInjectKey = handlers;
|
|
|
348
357
|
const contextStorageQueryHandlerInjectKey = contextStorageQueryHandler;
|
|
349
358
|
|
|
350
359
|
//#endregion
|
|
351
|
-
//#region src/
|
|
352
|
-
|
|
360
|
+
//#region src/composables/useContextStorageActivator.ts
|
|
361
|
+
function useContextStorageCollection$2() {
|
|
353
362
|
const collection$1 = inject(contextStorageCollectionInjectKey);
|
|
354
363
|
const item = inject(contextStorageCollectionItemInjectKey);
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
364
|
+
return { activate: () => collection$1.setActive(item) };
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
//#endregion
|
|
368
|
+
//#region src/components/ContextStorageActivator.vue?vue&type=script&lang.ts
|
|
369
|
+
var ContextStorageActivator_vue_vue_type_script_lang_default = defineComponent({ setup(_, { slots }) {
|
|
370
|
+
const { activate } = useContextStorageCollection$2();
|
|
371
|
+
return () => h("div", { onMousedown: activate }, slots.default?.());
|
|
359
372
|
} });
|
|
360
373
|
|
|
361
374
|
//#endregion
|
|
@@ -366,6 +379,14 @@ var ContextStorageActivator_default = ContextStorageActivator_vue_vue_type_scrip
|
|
|
366
379
|
//#region src/constants.ts
|
|
367
380
|
const defaultHandlers = [ContextStorageQueryHandler];
|
|
368
381
|
|
|
382
|
+
//#endregion
|
|
383
|
+
//#region src/composables/useContextStorageCollection.ts
|
|
384
|
+
function useContextStorageCollection$1(handlers$1) {
|
|
385
|
+
const collection$1 = new CollectionManager(handlers$1);
|
|
386
|
+
provide(contextStorageCollectionInjectKey, collection$1);
|
|
387
|
+
return collection$1;
|
|
388
|
+
}
|
|
389
|
+
|
|
369
390
|
//#endregion
|
|
370
391
|
//#region src/components/ContextStorageCollection.vue?vue&type=script&lang.ts
|
|
371
392
|
var ContextStorageCollection_vue_vue_type_script_lang_default = defineComponent({
|
|
@@ -374,46 +395,11 @@ var ContextStorageCollection_vue_vue_type_script_lang_default = defineComponent(
|
|
|
374
395
|
default: () => defaultHandlers
|
|
375
396
|
} },
|
|
376
397
|
setup({ handlers: handlers$1 }, { slots }) {
|
|
377
|
-
const lastActive = computed({
|
|
378
|
-
get: () => localStorage.getItem("context-storage-last-active") || "main",
|
|
379
|
-
set: (value) => localStorage.setItem("context-storage-last-active", value)
|
|
380
|
-
});
|
|
381
398
|
const router = useRouter();
|
|
382
|
-
const
|
|
383
|
-
const initialNavigatorStateResolvers = /* @__PURE__ */ new Map();
|
|
384
|
-
handlers$1.forEach((handler) => {
|
|
385
|
-
if (!handler.getInitialStateResolver) return;
|
|
386
|
-
initialNavigatorStateResolvers.set(handler, handler.getInitialStateResolver());
|
|
387
|
-
});
|
|
399
|
+
const collection$1 = useContextStorageCollection$1(handlers$1);
|
|
388
400
|
router.isReady().then(() => {
|
|
389
|
-
|
|
390
|
-
initialNavigatorState.set(handler, resolver());
|
|
391
|
-
});
|
|
392
|
-
activateLastActiveItem();
|
|
393
|
-
});
|
|
394
|
-
const collection$1 = new ContextStorageCollection(handlers$1);
|
|
395
|
-
collection$1.onActiveChange((item) => {
|
|
396
|
-
lastActive.value = item.key;
|
|
401
|
+
collection$1.markAsReady();
|
|
397
402
|
});
|
|
398
|
-
provide(contextStorageCollectionInjectKey, collection$1);
|
|
399
|
-
const activateInitialItem = (item) => {
|
|
400
|
-
item.handlers.forEach((handler) => {
|
|
401
|
-
const state = initialNavigatorState.get(handler.constructor);
|
|
402
|
-
if (!state) return;
|
|
403
|
-
handler.setInitialState?.(state);
|
|
404
|
-
});
|
|
405
|
-
collection$1.setActive(item);
|
|
406
|
-
};
|
|
407
|
-
const activateLastActiveItem = () => {
|
|
408
|
-
const lastActiveItem = collection$1.findItemByKey(lastActive.value);
|
|
409
|
-
if (lastActiveItem) {
|
|
410
|
-
activateInitialItem(lastActiveItem);
|
|
411
|
-
return;
|
|
412
|
-
}
|
|
413
|
-
const firstItem = collection$1.first();
|
|
414
|
-
if (!firstItem) throw new Error("[ContextStorage] Cannot find first item in collection");
|
|
415
|
-
activateInitialItem(firstItem);
|
|
416
|
-
};
|
|
417
403
|
return () => {
|
|
418
404
|
return slots.default?.();
|
|
419
405
|
};
|
|
@@ -424,6 +410,22 @@ var ContextStorageCollection_vue_vue_type_script_lang_default = defineComponent(
|
|
|
424
410
|
//#region src/components/ContextStorageCollection.vue
|
|
425
411
|
var ContextStorageCollection_default = ContextStorageCollection_vue_vue_type_script_lang_default;
|
|
426
412
|
|
|
413
|
+
//#endregion
|
|
414
|
+
//#region src/composables/useContextStorageProvider.ts
|
|
415
|
+
function useContextStorageCollection(key) {
|
|
416
|
+
const collection$1 = inject(contextStorageCollectionInjectKey);
|
|
417
|
+
if (!collection$1) throw new Error("[vue-context-storage] Context storage collection not found");
|
|
418
|
+
const item = collection$1.add({ key });
|
|
419
|
+
provide(contextStorageCollectionItemInjectKey, item);
|
|
420
|
+
provide(contextStorageHandlersInjectKey, item.handlers);
|
|
421
|
+
item.handlers.forEach((handler) => {
|
|
422
|
+
provide(handler.getInjectionKey(), handler);
|
|
423
|
+
});
|
|
424
|
+
onUnmounted(() => {
|
|
425
|
+
collection$1.remove(item);
|
|
426
|
+
});
|
|
427
|
+
}
|
|
428
|
+
|
|
427
429
|
//#endregion
|
|
428
430
|
//#region src/components/ContextStorageProvider.vue?vue&type=script&lang.ts
|
|
429
431
|
var ContextStorageProvider_vue_vue_type_script_lang_default = defineComponent({
|
|
@@ -432,17 +434,7 @@ var ContextStorageProvider_vue_vue_type_script_lang_default = defineComponent({
|
|
|
432
434
|
required: true
|
|
433
435
|
} },
|
|
434
436
|
setup(props, { slots }) {
|
|
435
|
-
|
|
436
|
-
if (!collection$1) throw new Error("[ContextStorage] Context storage collection not found");
|
|
437
|
-
const item = collection$1.add({ key: props.itemKey });
|
|
438
|
-
provide(contextStorageCollectionItemInjectKey, item);
|
|
439
|
-
provide(contextStorageHandlersInjectKey, item.handlers);
|
|
440
|
-
item.handlers.forEach((handler) => {
|
|
441
|
-
provide(handler.getInjectionKey(), handler);
|
|
442
|
-
});
|
|
443
|
-
onUnmounted(() => {
|
|
444
|
-
collection$1.remove(item);
|
|
445
|
-
});
|
|
437
|
+
useContextStorageCollection(props.itemKey);
|
|
446
438
|
return () => slots.default?.();
|
|
447
439
|
}
|
|
448
440
|
});
|
|
@@ -453,6 +445,7 @@ var ContextStorageProvider_default = ContextStorageProvider_vue_vue_type_script_
|
|
|
453
445
|
|
|
454
446
|
//#endregion
|
|
455
447
|
//#region src/components/ContextStorage.vue?vue&type=script&setup=true&lang.ts
|
|
448
|
+
const itemKey = "main";
|
|
456
449
|
var ContextStorage_vue_vue_type_script_setup_true_lang_default = /* @__PURE__ */ defineComponent({
|
|
457
450
|
__name: "ContextStorage",
|
|
458
451
|
props: { handlers: {
|
|
@@ -461,17 +454,41 @@ var ContextStorage_vue_vue_type_script_setup_true_lang_default = /* @__PURE__ */
|
|
|
461
454
|
default: () => defaultHandlers
|
|
462
455
|
} },
|
|
463
456
|
setup(__props) {
|
|
457
|
+
const router = useRouter();
|
|
458
|
+
const collection$1 = useContextStorageCollection$1(__props.handlers);
|
|
459
|
+
const initialNavigatorState = /* @__PURE__ */ new Map();
|
|
460
|
+
const initialNavigatorStateResolvers = /* @__PURE__ */ new Map();
|
|
461
|
+
__props.handlers.forEach((handler) => {
|
|
462
|
+
if (!handler.getInitialStateResolver) return;
|
|
463
|
+
initialNavigatorStateResolvers.set(handler, handler.getInitialStateResolver());
|
|
464
|
+
});
|
|
465
|
+
const activateMainItem = () => {
|
|
466
|
+
const item = collection$1.findItemByKey(itemKey);
|
|
467
|
+
if (!item) throw new Error(`[vue-context-storage] Cannot find "${itemKey}" item in collection`);
|
|
468
|
+
item.handlers.forEach((handler) => {
|
|
469
|
+
const state = initialNavigatorState.get(handler.constructor);
|
|
470
|
+
if (!state) return;
|
|
471
|
+
handler.setInitialState?.(state);
|
|
472
|
+
});
|
|
473
|
+
collection$1.setActive(item);
|
|
474
|
+
};
|
|
475
|
+
router.isReady().then(() => {
|
|
476
|
+
collection$1.markAsReady();
|
|
477
|
+
});
|
|
478
|
+
collection$1.isReady().then(() => {
|
|
479
|
+
initialNavigatorStateResolvers.forEach((resolver, handler) => {
|
|
480
|
+
initialNavigatorState.set(handler, resolver());
|
|
481
|
+
});
|
|
482
|
+
activateMainItem();
|
|
483
|
+
});
|
|
464
484
|
return (_ctx, _cache) => {
|
|
465
|
-
return openBlock(), createBlock(
|
|
466
|
-
default: withCtx(() => [createVNode(
|
|
467
|
-
default: withCtx(() => [
|
|
468
|
-
default: withCtx(() => [renderSlot(_ctx.$slots, "default")]),
|
|
469
|
-
_: 3
|
|
470
|
-
})]),
|
|
485
|
+
return openBlock(), createBlock(ContextStorageProvider_default, { "item-key": itemKey }, {
|
|
486
|
+
default: withCtx(() => [createVNode(ContextStorageActivator_default, null, {
|
|
487
|
+
default: withCtx(() => [renderSlot(_ctx.$slots, "default")]),
|
|
471
488
|
_: 3
|
|
472
489
|
})]),
|
|
473
490
|
_: 3
|
|
474
|
-
}
|
|
491
|
+
});
|
|
475
492
|
};
|
|
476
493
|
}
|
|
477
494
|
});
|
|
@@ -552,4 +569,4 @@ const transform = {
|
|
|
552
569
|
};
|
|
553
570
|
|
|
554
571
|
//#endregion
|
|
555
|
-
export { ContextStorage_default as ContextStorage, ContextStorageActivator_default as ContextStorageActivator, ContextStorageCollection_default as ContextStorageCollection, ContextStorageProvider_default as ContextStorageProvider, ContextStorageQueryHandler, VueContextStoragePlugin, asArray, asBoolean, asNumber, asNumberArray, asString, collection, collectionItem, contextStorageCollectionInjectKey, contextStorageCollectionItemInjectKey, contextStorageHandlersInjectKey, contextStorageQueryHandler, contextStorageQueryHandlerInjectKey, defaultHandlers,
|
|
572
|
+
export { CollectionManager, ContextStorage_default as ContextStorage, ContextStorageActivator_default as ContextStorageActivator, ContextStorageCollection_default as ContextStorageCollection, ContextStorageProvider_default as ContextStorageProvider, ContextStorageQueryHandler, VueContextStoragePlugin, asArray, asBoolean, asNumber, asNumberArray, asString, collection, collectionItem, contextStorageCollectionInjectKey, contextStorageCollectionItemInjectKey, contextStorageHandlersInjectKey, contextStorageQueryHandler, contextStorageQueryHandlerInjectKey, defaultHandlers, handlers, transform, useContextStorageQueryHandler };
|