@esmx/router-vue 3.0.0-rc.16 → 3.0.0-rc.19
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/LICENSE +1 -1
- package/README.md +563 -0
- package/README.zh-CN.md +563 -0
- package/dist/index.d.ts +6 -4
- package/dist/index.mjs +11 -4
- package/dist/index.test.d.ts +1 -0
- package/dist/index.test.mjs +206 -0
- package/dist/plugin.d.ts +55 -11
- package/dist/plugin.mjs +32 -16
- package/dist/plugin.test.d.ts +1 -0
- package/dist/plugin.test.mjs +436 -0
- package/dist/router-link.d.ts +202 -0
- package/dist/router-link.mjs +84 -0
- package/dist/router-link.test.d.ts +1 -0
- package/dist/router-link.test.mjs +456 -0
- package/dist/router-view.d.ts +30 -0
- package/dist/router-view.mjs +17 -0
- package/dist/router-view.test.d.ts +1 -0
- package/dist/router-view.test.mjs +459 -0
- package/dist/use.d.ts +198 -3
- package/dist/use.mjs +75 -9
- package/dist/use.test.d.ts +1 -0
- package/dist/use.test.mjs +461 -0
- package/dist/util.d.ts +7 -0
- package/dist/util.mjs +24 -0
- package/dist/util.test.d.ts +1 -0
- package/dist/util.test.mjs +319 -0
- package/dist/vue2.d.ts +13 -0
- package/dist/vue2.mjs +0 -0
- package/dist/vue3.d.ts +13 -0
- package/dist/vue3.mjs +0 -0
- package/package.json +31 -14
- package/src/index.test.ts +263 -0
- package/src/index.ts +16 -4
- package/src/plugin.test.ts +574 -0
- package/src/plugin.ts +86 -31
- package/src/router-link.test.ts +569 -0
- package/src/router-link.ts +148 -0
- package/src/router-view.test.ts +599 -0
- package/src/router-view.ts +61 -0
- package/src/use.test.ts +616 -0
- package/src/use.ts +307 -11
- package/src/util.test.ts +418 -0
- package/src/util.ts +32 -0
- package/src/vue2.ts +16 -0
- package/src/vue3.ts +15 -0
- package/dist/link.d.ts +0 -101
- package/dist/link.mjs +0 -103
- package/dist/symbols.d.ts +0 -3
- package/dist/symbols.mjs +0 -3
- package/dist/view.d.ts +0 -21
- package/dist/view.mjs +0 -75
- package/src/link.ts +0 -177
- package/src/symbols.ts +0 -8
- package/src/view.ts +0 -95
package/src/use.ts
CHANGED
|
@@ -1,20 +1,316 @@
|
|
|
1
|
-
import type { Route,
|
|
2
|
-
import {
|
|
1
|
+
import type { Route, Router, RouterLinkProps } from '@esmx/router';
|
|
2
|
+
import {
|
|
3
|
+
type Ref,
|
|
4
|
+
computed,
|
|
5
|
+
getCurrentInstance,
|
|
6
|
+
inject,
|
|
7
|
+
onBeforeUnmount,
|
|
8
|
+
provide,
|
|
9
|
+
ref
|
|
10
|
+
} from 'vue';
|
|
11
|
+
import { createSymbolProperty } from './util';
|
|
3
12
|
|
|
4
|
-
|
|
13
|
+
export interface VueInstance {
|
|
14
|
+
$parent?: VueInstance | null;
|
|
15
|
+
$root?: VueInstance | null;
|
|
16
|
+
$children?: VueInstance[] | null;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
interface RouterContext {
|
|
20
|
+
router: Router;
|
|
21
|
+
route: Ref<Route>;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const ROUTER_CONTEXT_KEY = Symbol('router-context');
|
|
25
|
+
const ROUTER_INJECT_KEY = Symbol('router-inject');
|
|
26
|
+
|
|
27
|
+
const ERROR_MESSAGES = {
|
|
28
|
+
SETUP_ONLY: (fnName: string) =>
|
|
29
|
+
`[@esmx/router-vue] ${fnName}() can only be called during setup()`,
|
|
30
|
+
CONTEXT_NOT_FOUND:
|
|
31
|
+
'[@esmx/router-vue] Router context not found. ' +
|
|
32
|
+
'Please ensure useProvideRouter() is called in a parent component.'
|
|
33
|
+
} as const;
|
|
34
|
+
|
|
35
|
+
const routerContextProperty =
|
|
36
|
+
createSymbolProperty<RouterContext>(ROUTER_CONTEXT_KEY);
|
|
37
|
+
|
|
38
|
+
function getCurrentProxy(functionName: string): VueInstance {
|
|
39
|
+
const instance = getCurrentInstance();
|
|
40
|
+
if (!instance || !instance.proxy) {
|
|
41
|
+
throw new Error(ERROR_MESSAGES.SETUP_ONLY(functionName));
|
|
42
|
+
}
|
|
43
|
+
return instance.proxy;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function findRouterContext(vm?: VueInstance): RouterContext {
|
|
47
|
+
// If no vm provided, try to get current instance
|
|
48
|
+
if (!vm) {
|
|
49
|
+
vm = getCurrentProxy('findRouterContext');
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
let context = routerContextProperty.get(vm);
|
|
53
|
+
if (context) {
|
|
54
|
+
return context;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
let current = vm.$parent;
|
|
58
|
+
while (current) {
|
|
59
|
+
context = routerContextProperty.get(current);
|
|
60
|
+
if (context) {
|
|
61
|
+
routerContextProperty.set(vm, context);
|
|
62
|
+
return context;
|
|
63
|
+
}
|
|
64
|
+
current = current.$parent;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
throw new Error(ERROR_MESSAGES.CONTEXT_NOT_FOUND);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Get router instance from a Vue component instance.
|
|
72
|
+
* This is a lower-level function used internally by useRouter().
|
|
73
|
+
* Use this in Options API, use useRouter() in Composition API.
|
|
74
|
+
*
|
|
75
|
+
* @param instance - Vue component instance (optional, will use getCurrentInstance if not provided)
|
|
76
|
+
* @returns Router instance
|
|
77
|
+
* @throws {Error} If router context is not found
|
|
78
|
+
*
|
|
79
|
+
* @example
|
|
80
|
+
* ```typescript
|
|
81
|
+
* // Options API usage
|
|
82
|
+
* import { defineComponent } from 'vue';
|
|
83
|
+
* import { getRouter } from '@esmx/router-vue';
|
|
84
|
+
*
|
|
85
|
+
* export default defineComponent({
|
|
86
|
+
* mounted() {
|
|
87
|
+
* const router = getRouter(this);
|
|
88
|
+
* router.push('/dashboard');
|
|
89
|
+
* },
|
|
90
|
+
* methods: {
|
|
91
|
+
* handleNavigation() {
|
|
92
|
+
* const router = getRouter(this);
|
|
93
|
+
* router.replace('/profile');
|
|
94
|
+
* }
|
|
95
|
+
* }
|
|
96
|
+
* });
|
|
97
|
+
*
|
|
98
|
+
* // Can also be called without instance (uses getCurrentInstance internally)
|
|
99
|
+
* const router = getRouter(); // Works in globalProperties getters
|
|
100
|
+
* ```
|
|
101
|
+
*/
|
|
102
|
+
export function getRouter(instance?: VueInstance): Router {
|
|
103
|
+
return findRouterContext(instance).router;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Get current route from a Vue component instance.
|
|
108
|
+
* This is a lower-level function used internally by useRoute().
|
|
109
|
+
* Use this in Options API, use useRoute() in Composition API.
|
|
110
|
+
*
|
|
111
|
+
* @param instance - Vue component instance (optional, will use getCurrentInstance if not provided)
|
|
112
|
+
* @returns Current route object
|
|
113
|
+
* @throws {Error} If router context is not found
|
|
114
|
+
*
|
|
115
|
+
* @example
|
|
116
|
+
* ```typescript
|
|
117
|
+
* // Options API usage
|
|
118
|
+
* import { defineComponent } from 'vue';
|
|
119
|
+
* import { getRoute } from '@esmx/router-vue';
|
|
120
|
+
*
|
|
121
|
+
* export default defineComponent({
|
|
122
|
+
* computed: {
|
|
123
|
+
* routeInfo() {
|
|
124
|
+
* const route = getRoute(this);
|
|
125
|
+
* return {
|
|
126
|
+
* path: route.path,
|
|
127
|
+
* params: route.params,
|
|
128
|
+
* query: route.query
|
|
129
|
+
* };
|
|
130
|
+
* }
|
|
131
|
+
* }
|
|
132
|
+
* });
|
|
133
|
+
*
|
|
134
|
+
* // Can also be called without instance (uses getCurrentInstance internally)
|
|
135
|
+
* const route = getRoute(); // Works in globalProperties getters
|
|
136
|
+
* ```
|
|
137
|
+
*/
|
|
138
|
+
export function getRoute(instance?: VueInstance): Route {
|
|
139
|
+
return findRouterContext(instance).route.value;
|
|
140
|
+
}
|
|
5
141
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
142
|
+
/**
|
|
143
|
+
* Get router context using the optimal method available.
|
|
144
|
+
* First tries provide/inject (works in setup), then falls back to hierarchy traversal.
|
|
145
|
+
*/
|
|
146
|
+
function useRouterContext(functionName: string): RouterContext {
|
|
147
|
+
// First try to get context from provide/inject (works in setup)
|
|
148
|
+
const injectedContext = inject<RouterContext>(ROUTER_INJECT_KEY);
|
|
149
|
+
if (injectedContext) {
|
|
150
|
+
return injectedContext;
|
|
11
151
|
}
|
|
152
|
+
|
|
153
|
+
// Fallback to component hierarchy traversal (works after mount)
|
|
154
|
+
const proxy = getCurrentProxy(functionName);
|
|
155
|
+
return findRouterContext(proxy);
|
|
12
156
|
}
|
|
13
157
|
|
|
14
|
-
|
|
15
|
-
|
|
158
|
+
/**
|
|
159
|
+
* Get the router instance in a Vue component.
|
|
160
|
+
* Must be called within setup() or other composition functions.
|
|
161
|
+
* Use this in Composition API, use getRouter() in Options API.
|
|
162
|
+
*
|
|
163
|
+
* @returns Router instance for navigation and route management
|
|
164
|
+
* @throws {Error} If called outside setup() or router context not found
|
|
165
|
+
*
|
|
166
|
+
* @example
|
|
167
|
+
* ```vue
|
|
168
|
+
* <script setup lang="ts">
|
|
169
|
+
* import { useRouter } from '@esmx/router-vue';
|
|
170
|
+
*
|
|
171
|
+
* const router = useRouter();
|
|
172
|
+
*
|
|
173
|
+
* const navigateToHome = () => {
|
|
174
|
+
* router.push('/home');
|
|
175
|
+
* };
|
|
176
|
+
*
|
|
177
|
+
* const goBack = () => {
|
|
178
|
+
* router.back();
|
|
179
|
+
* };
|
|
180
|
+
*
|
|
181
|
+
* const navigateWithQuery = () => {
|
|
182
|
+
* router.push({
|
|
183
|
+
* path: '/search',
|
|
184
|
+
* query: { q: 'vue router', page: '1' }
|
|
185
|
+
* });
|
|
186
|
+
* };
|
|
187
|
+
* </script>
|
|
188
|
+
* ```
|
|
189
|
+
*/
|
|
190
|
+
export function useRouter(): Router {
|
|
191
|
+
return useRouterContext('useRouter').router;
|
|
16
192
|
}
|
|
17
193
|
|
|
194
|
+
/**
|
|
195
|
+
* Get the current route information in a Vue component.
|
|
196
|
+
* Returns a reactive reference that automatically updates when the route changes.
|
|
197
|
+
* Must be called within setup() or other composition functions.
|
|
198
|
+
* Use this in Composition API, use getRoute() in Options API.
|
|
199
|
+
*
|
|
200
|
+
* @returns Current route object with path, params, query, etc.
|
|
201
|
+
* @throws {Error} If called outside setup() or router context not found
|
|
202
|
+
*
|
|
203
|
+
* @example
|
|
204
|
+
* ```vue
|
|
205
|
+
* <template>
|
|
206
|
+
* <div>
|
|
207
|
+
* <h1>{{ route.meta?.title || 'Page' }}</h1>
|
|
208
|
+
* <p>Path: {{ route.path }}</p>
|
|
209
|
+
* <p>Params: {{ JSON.stringify(route.params) }}</p>
|
|
210
|
+
* <p>Query: {{ JSON.stringify(route.query) }}</p>
|
|
211
|
+
* </div>
|
|
212
|
+
* </template>
|
|
213
|
+
*
|
|
214
|
+
* <script setup lang="ts">
|
|
215
|
+
* import { useRoute } from '@esmx/router-vue';
|
|
216
|
+
* import { watch } from 'vue';
|
|
217
|
+
*
|
|
218
|
+
* const route = useRoute();
|
|
219
|
+
*
|
|
220
|
+
* watch(() => route.path, (newPath) => {
|
|
221
|
+
* console.log('Route changed to:', newPath);
|
|
222
|
+
* });
|
|
223
|
+
* </script>
|
|
224
|
+
* ```
|
|
225
|
+
*/
|
|
18
226
|
export function useRoute(): Route {
|
|
19
|
-
return
|
|
227
|
+
return useRouterContext('useRoute').route.value;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
/**
|
|
231
|
+
* Provide router context to child components.
|
|
232
|
+
* This must be called in a parent component to make the router available
|
|
233
|
+
* to child components via useRouter() and useRoute().
|
|
234
|
+
*
|
|
235
|
+
* @param router - Router instance to provide to child components
|
|
236
|
+
* @throws {Error} If called outside setup()
|
|
237
|
+
*
|
|
238
|
+
* @example
|
|
239
|
+
* ```typescript
|
|
240
|
+
* // Vue 3 usage
|
|
241
|
+
* import { createApp } from 'vue';
|
|
242
|
+
* import { Router } from '@esmx/router';
|
|
243
|
+
* import { useProvideRouter } from '@esmx/router-vue';
|
|
244
|
+
*
|
|
245
|
+
* const routes = [
|
|
246
|
+
* { path: '/', component: () => import('./Home.vue') },
|
|
247
|
+
* { path: '/about', component: () => import('./About.vue') }
|
|
248
|
+
* ];
|
|
249
|
+
*
|
|
250
|
+
* const router = new Router({ routes });
|
|
251
|
+
* const app = createApp({
|
|
252
|
+
* setup() {
|
|
253
|
+
* useProvideRouter(router);
|
|
254
|
+
* }
|
|
255
|
+
* });
|
|
256
|
+
* app.mount('#app');
|
|
257
|
+
* ```
|
|
258
|
+
*/
|
|
259
|
+
export function useProvideRouter(router: Router): void {
|
|
260
|
+
const proxy = getCurrentProxy('useProvideRouter');
|
|
261
|
+
|
|
262
|
+
const context: RouterContext = {
|
|
263
|
+
router,
|
|
264
|
+
route: ref(router.route) as Ref<Route>
|
|
265
|
+
};
|
|
266
|
+
|
|
267
|
+
// Provide context via Vue 3's provide/inject (works in setup)
|
|
268
|
+
provide(ROUTER_INJECT_KEY, context);
|
|
269
|
+
|
|
270
|
+
// Also set on component instance for fallback (works after mount)
|
|
271
|
+
routerContextProperty.set(proxy, context);
|
|
272
|
+
|
|
273
|
+
const unwatch = router.afterEach((to: Route) => {
|
|
274
|
+
if (router.route === to) {
|
|
275
|
+
to.syncTo(context.route.value);
|
|
276
|
+
}
|
|
277
|
+
});
|
|
278
|
+
|
|
279
|
+
onBeforeUnmount(unwatch);
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
/**
|
|
283
|
+
* Create reactive link helpers for navigation elements.
|
|
284
|
+
* Returns computed properties for link attributes, classes, and event handlers.
|
|
285
|
+
*
|
|
286
|
+
* @param props - RouterLink properties configuration
|
|
287
|
+
* @returns Computed link resolver with attributes and event handlers
|
|
288
|
+
*
|
|
289
|
+
* @example
|
|
290
|
+
* ```vue
|
|
291
|
+
* <template>
|
|
292
|
+
* <a
|
|
293
|
+
* v-bind="link.attributes"
|
|
294
|
+
* v-on="link.getEventHandlers()"
|
|
295
|
+
* :class="{ active: link.isActive }"
|
|
296
|
+
* >
|
|
297
|
+
* Home
|
|
298
|
+
* </a>
|
|
299
|
+
* </template>
|
|
300
|
+
*
|
|
301
|
+
* <script setup lang="ts">
|
|
302
|
+
* import { useLink } from '@esmx/router-vue';
|
|
303
|
+
*
|
|
304
|
+
* const link = useLink({
|
|
305
|
+
* to: '/home',
|
|
306
|
+
* type: 'push',
|
|
307
|
+
* exact: 'include'
|
|
308
|
+
* }).value;
|
|
309
|
+
* </script>
|
|
310
|
+
* ```
|
|
311
|
+
*/
|
|
312
|
+
export function useLink(props: RouterLinkProps) {
|
|
313
|
+
const router = useRouter();
|
|
314
|
+
|
|
315
|
+
return computed(() => router.resolveLink(props));
|
|
20
316
|
}
|