vue-router-query-sync 0.0.13 → 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +46 -8
- package/dist/composables/useQuerySync.d.ts +10 -10
- package/dist/composables/useQuerySync.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.mjs +41 -32
- package/package.json +6 -2
package/README.md
CHANGED
|
@@ -16,14 +16,22 @@
|
|
|
16
16
|
|
|
17
17
|
- Changes in your store update the URL query.
|
|
18
18
|
- Changes in the URL query update your store.
|
|
19
|
-
- Batched updates
|
|
19
|
+
- Batched updates prevent excessive `router.replace` calls.
|
|
20
20
|
|
|
21
21
|
---
|
|
22
22
|
|
|
23
|
+
## 💡 Why use this plugin?
|
|
24
|
+
|
|
25
|
+
- 🔄 Keeps your app state and URL perfectly in sync — no more manual watchers or `router.replace` logic.
|
|
26
|
+
- 🧠 Works with **Pinia**, **local refs**, or any reactive source.
|
|
27
|
+
- 🧩 Handles multiple query keys and isolated contexts safely.
|
|
28
|
+
- ⚙️ Fully typed with TypeScript and designed for Vue 3’s Composition API.
|
|
29
|
+
- 🚀 Tiny footprint — optimized for production.
|
|
30
|
+
|
|
23
31
|
## ✅ Requirements
|
|
24
32
|
|
|
25
|
-
- Vue 3
|
|
26
|
-
- Vue Router 4
|
|
33
|
+
- Vue 3
|
|
34
|
+
- Vue Router 4
|
|
27
35
|
|
|
28
36
|
---
|
|
29
37
|
|
|
@@ -63,11 +71,15 @@ createApp(App)
|
|
|
63
71
|
|
|
64
72
|
## 🧩 Basic Usage
|
|
65
73
|
|
|
66
|
-
|
|
74
|
+
You can use `useQuerySync` several times in one component.
|
|
75
|
+
|
|
76
|
+
#### Sync a value with a query param named `tab`:
|
|
77
|
+
|
|
78
|
+
- Visiting `?tab=favorite` sets `tab.value = 'favorite'`.
|
|
79
|
+
- Changing `tab.value = 'all'` updates the URL to `?tab=all`.
|
|
67
80
|
|
|
68
81
|
```ts
|
|
69
82
|
import { useQuerySync } from 'vue-router-query-sync'
|
|
70
|
-
import { ref } from 'vue'
|
|
71
83
|
|
|
72
84
|
const tab = ref<'favorite' | 'all'>('all')
|
|
73
85
|
|
|
@@ -78,10 +90,36 @@ useQuerySync(
|
|
|
78
90
|
)
|
|
79
91
|
```
|
|
80
92
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
93
|
+
### Multiple values
|
|
94
|
+
#### Sync a value with a query param named `brands`:
|
|
95
|
+
|
|
96
|
+
- Visiting `?brands=lg%samsung` sets `brands.value = ['lg', 'samsung']`.
|
|
97
|
+
- Changing `brands.value = ['lg']` updates the URL to `?brands=lg`.
|
|
84
98
|
|
|
99
|
+
```ts
|
|
100
|
+
import { useQuerySync } from 'vue-router-query-sync'
|
|
101
|
+
|
|
102
|
+
const brands = [
|
|
103
|
+
{ value: 'lg', label: 'LG' },
|
|
104
|
+
{ value: 'samsung', label: 'Samsung' }
|
|
105
|
+
]
|
|
106
|
+
|
|
107
|
+
const selectedBrands = ref<string[]>([])
|
|
108
|
+
|
|
109
|
+
useQuerySync(
|
|
110
|
+
'brands',
|
|
111
|
+
() => {
|
|
112
|
+
return selectedBrands.value.length > 0 ? selectedBrands.value.join('%') : null
|
|
113
|
+
},
|
|
114
|
+
(val) => {
|
|
115
|
+
if (typeof val === 'string' && val) {
|
|
116
|
+
selectedBrands.value = val.includes('%') ? val.split('%') : [val]
|
|
117
|
+
} else {
|
|
118
|
+
selectedBrands.value = []
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
)
|
|
122
|
+
```
|
|
85
123
|
---
|
|
86
124
|
|
|
87
125
|
## 🔧 API
|
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
import { QuerySyncOptions } from '../types';
|
|
2
2
|
/**
|
|
3
|
-
*
|
|
3
|
+
* Synchronizes a store value with a query parameter in the URL.
|
|
4
4
|
*
|
|
5
|
-
* @param key -
|
|
6
|
-
* @param get -
|
|
7
|
-
* @param set -
|
|
8
|
-
* @param options.deps -
|
|
9
|
-
* @param options.context -
|
|
5
|
+
* @param key - The name of the query parameter, e.g. "tab".
|
|
6
|
+
* @param get - A function that returns the current value from the store.
|
|
7
|
+
* @param set - A function that updates the value in the store.
|
|
8
|
+
* @param options.deps - A list of reactive dependencies that must change before synchronization occurs.
|
|
9
|
+
* @param options.context - A unique context identifier, required when multiple instances use the same query key on the same page.
|
|
10
10
|
*
|
|
11
|
-
* ⚠️
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
11
|
+
* ⚠️ Important:
|
|
12
|
+
* If multiple components on the same page use the same query key,
|
|
13
|
+
* you must provide a unique `context` to prevent conflicts.
|
|
14
|
+
* Alternatively, always use unique query keys (for example, instead of "page", use "usersPage").
|
|
15
15
|
*/
|
|
16
16
|
export declare function useQuerySync<T extends string | number>(key: string, get: () => T | null, set: (val: T) => void, options?: QuerySyncOptions): void;
|
|
17
17
|
//# sourceMappingURL=useQuerySync.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useQuerySync.d.ts","sourceRoot":"","sources":["../../src/composables/useQuerySync.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAA;
|
|
1
|
+
{"version":3,"file":"useQuerySync.d.ts","sourceRoot":"","sources":["../../src/composables/useQuerySync.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAA;AAgB1C;;;;;;;;;;;;;GAaG;AACH,wBAAgB,YAAY,CAAC,CAAC,SAAS,MAAM,GAAG,MAAM,EACpD,GAAG,EAAE,MAAM,EACX,GAAG,EAAE,MAAM,CAAC,GAAG,IAAI,EACnB,GAAG,EAAE,CAAC,GAAG,EAAE,CAAC,KAAK,IAAI,EACrB,OAAO,GAAE,gBAAqB,QAiE/B"}
|
package/dist/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
(function(
|
|
1
|
+
(function(u,n){typeof exports=="object"&&typeof module<"u"?n(exports,require("vue")):typeof define=="function"&&define.amd?define(["exports","vue"],n):(u=typeof globalThis<"u"?globalThis:u||self,n(u.VueRouterQuerySync={},u.Vue))})(this,(function(u,n){"use strict";let p=null;function m(e){p=e}function Q(){if(!p)throw new Error("[vue-router-query-sync] Router instance not set. Call setRouter(router) before using composables.");return p}let c={};const f=new Set;let R=!1;function l(e,t){const a=Q();t===null?e in c||f.add(e):(c[e]=t,f.delete(e)),R||(R=!0,queueMicrotask(()=>{const d={...a.currentRoute.value.query};f.forEach(i=>{delete d[i]});const q={...d,...c};a.replace({query:q}),c={},f.clear(),R=!1}))}function g(e){if(e==="")return e;const t=Number(e);return isNaN(t)?e:t}function T(e,t,a,d={}){const i=Q().currentRoute,{deps:v=[],context:b}=d,r=b?`${b}_${e}`:e,S=(o,y=!1)=>{if(typeof o=="string"){const s=g(o);if(y||s!==t()){a(s);const h=t();h!==s&&h!==null&&l(r,h)}}else if(o===void 0){const s=t();s!==null&&l(r,s)}},M=o=>{const y=i.value.query[r];if(o===null)y!==void 0&&l(r,null);else{const s=String(o);y!==s&&l(r,o)}};n.onBeforeMount(()=>{v.length>0?n.watch(v,()=>S(i.value.query[r])):S(i.value.query[r])}),n.watch(t,M),n.watch(()=>i.value.query[r],o=>S(o)),n.onBeforeUnmount(()=>{l(r,null)})}const w={install(e,t){m(t.router)}};u.default=w,u.getRouter=Q,u.setRouter=m,u.useQuerySync=T,Object.defineProperties(u,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}})}));
|
package/dist/index.mjs
CHANGED
|
@@ -1,68 +1,77 @@
|
|
|
1
|
-
import { onBeforeMount as
|
|
1
|
+
import { onBeforeMount as b, watch as y, onBeforeUnmount as g } from "vue";
|
|
2
2
|
let v = null;
|
|
3
3
|
function x(e) {
|
|
4
4
|
v = e;
|
|
5
5
|
}
|
|
6
|
-
function
|
|
6
|
+
function S() {
|
|
7
7
|
if (!v)
|
|
8
8
|
throw new Error(
|
|
9
9
|
"[vue-router-query-sync] Router instance not set. Call setRouter(router) before using composables."
|
|
10
10
|
);
|
|
11
11
|
return v;
|
|
12
12
|
}
|
|
13
|
-
let
|
|
13
|
+
let f = {};
|
|
14
14
|
const a = /* @__PURE__ */ new Set();
|
|
15
|
-
let
|
|
16
|
-
function l(e,
|
|
17
|
-
const s =
|
|
18
|
-
|
|
15
|
+
let Q = !1;
|
|
16
|
+
function l(e, t) {
|
|
17
|
+
const s = S();
|
|
18
|
+
t === null ? e in f || a.add(e) : (f[e] = t, a.delete(e)), Q || (Q = !0, queueMicrotask(() => {
|
|
19
19
|
const c = { ...s.currentRoute.value.query };
|
|
20
20
|
a.forEach((o) => {
|
|
21
21
|
delete c[o];
|
|
22
22
|
});
|
|
23
23
|
const R = {
|
|
24
24
|
...c,
|
|
25
|
-
...
|
|
25
|
+
...f
|
|
26
26
|
};
|
|
27
|
-
s.replace({ query: R }),
|
|
27
|
+
s.replace({ query: R }), f = {}, a.clear(), Q = !1;
|
|
28
28
|
}));
|
|
29
29
|
}
|
|
30
|
-
function
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
30
|
+
function N(e) {
|
|
31
|
+
if (e === "")
|
|
32
|
+
return e;
|
|
33
|
+
const t = Number(e);
|
|
34
|
+
return isNaN(t) ? e : t;
|
|
35
|
+
}
|
|
36
|
+
function B(e, t, s, c = {}) {
|
|
37
|
+
const o = S().currentRoute, { deps: m = [], context: q } = c, r = q ? `${q}_${e}` : e, d = (u, i = !1) => {
|
|
38
|
+
if (typeof u == "string") {
|
|
39
|
+
const n = N(u);
|
|
40
|
+
if (i || n !== t()) {
|
|
35
41
|
s(n);
|
|
36
|
-
const p =
|
|
42
|
+
const p = t();
|
|
37
43
|
p !== n && p !== null && l(r, p);
|
|
38
44
|
}
|
|
39
|
-
} else {
|
|
40
|
-
const n =
|
|
45
|
+
} else if (u === void 0) {
|
|
46
|
+
const n = t();
|
|
41
47
|
n !== null && l(r, n);
|
|
42
48
|
}
|
|
49
|
+
}, h = (u) => {
|
|
50
|
+
const i = o.value.query[r];
|
|
51
|
+
if (u === null)
|
|
52
|
+
i !== void 0 && l(r, null);
|
|
53
|
+
else {
|
|
54
|
+
const n = String(u);
|
|
55
|
+
i !== n && l(r, u);
|
|
56
|
+
}
|
|
43
57
|
};
|
|
44
|
-
|
|
58
|
+
b(() => {
|
|
45
59
|
m.length > 0 ? y(m, () => d(o.value.query[r])) : d(o.value.query[r]);
|
|
46
|
-
}), y(
|
|
47
|
-
const f = o.value.query[r];
|
|
48
|
-
t === null ? f !== void 0 && l(r, null) : f !== String(t) && l(r, t);
|
|
49
|
-
}), y(
|
|
60
|
+
}), y(t, h), y(
|
|
50
61
|
() => o.value.query[r],
|
|
51
|
-
(
|
|
52
|
-
|
|
53
|
-
}
|
|
54
|
-
), N(() => {
|
|
62
|
+
(u) => d(u)
|
|
63
|
+
), g(() => {
|
|
55
64
|
l(r, null);
|
|
56
65
|
});
|
|
57
66
|
}
|
|
58
|
-
const
|
|
59
|
-
install(e,
|
|
60
|
-
x(
|
|
67
|
+
const E = {
|
|
68
|
+
install(e, t) {
|
|
69
|
+
x(t.router);
|
|
61
70
|
}
|
|
62
71
|
};
|
|
63
72
|
export {
|
|
64
|
-
|
|
65
|
-
|
|
73
|
+
E as default,
|
|
74
|
+
S as getRouter,
|
|
66
75
|
x as setRouter,
|
|
67
|
-
|
|
76
|
+
B as useQuerySync
|
|
68
77
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vue-router-query-sync",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "1.0.1",
|
|
4
4
|
"description": "Vue composable for syncing router query params with store",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"module": "dist/index.mjs",
|
|
@@ -20,12 +20,16 @@
|
|
|
20
20
|
],
|
|
21
21
|
"keywords": [
|
|
22
22
|
"vue",
|
|
23
|
+
"vue3",
|
|
24
|
+
"vue plugin",
|
|
23
25
|
"router",
|
|
24
26
|
"query",
|
|
25
27
|
"sync",
|
|
26
28
|
"pinia",
|
|
27
29
|
"store",
|
|
28
|
-
"composable"
|
|
30
|
+
"composable",
|
|
31
|
+
"router query",
|
|
32
|
+
"query sync"
|
|
29
33
|
],
|
|
30
34
|
"author": "Ivan Chikachev <ivan-chikachev@mail.ru>",
|
|
31
35
|
"license": "MIT",
|