@esmx/router-vue 3.0.0-rc.17 → 3.0.0-rc.20
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 +61 -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 +31 -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 +92 -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 +62 -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
|
@@ -0,0 +1,459 @@
|
|
|
1
|
+
import { Router, RouterMode } from "@esmx/router";
|
|
2
|
+
import { afterEach, beforeEach, describe, expect, it } from "vitest";
|
|
3
|
+
import { createApp, defineComponent, h, inject, nextTick, provide } from "vue";
|
|
4
|
+
import { RouterView } from "./router-view.mjs";
|
|
5
|
+
import { useProvideRouter } from "./use.mjs";
|
|
6
|
+
const HomeComponent = defineComponent({
|
|
7
|
+
name: "HomeComponent",
|
|
8
|
+
setup() {
|
|
9
|
+
return () => h("div", { class: "home" }, "Home Page");
|
|
10
|
+
}
|
|
11
|
+
});
|
|
12
|
+
const AboutComponent = defineComponent({
|
|
13
|
+
name: "AboutComponent",
|
|
14
|
+
setup() {
|
|
15
|
+
return () => h("div", { class: "about" }, "About Page");
|
|
16
|
+
}
|
|
17
|
+
});
|
|
18
|
+
const UserComponent = defineComponent({
|
|
19
|
+
name: "UserComponent",
|
|
20
|
+
setup() {
|
|
21
|
+
return () => h("div", { class: "user" }, "User Component");
|
|
22
|
+
}
|
|
23
|
+
});
|
|
24
|
+
const ESModuleComponent = {
|
|
25
|
+
__esModule: true,
|
|
26
|
+
default: defineComponent({
|
|
27
|
+
name: "ESModuleComponent",
|
|
28
|
+
setup() {
|
|
29
|
+
return () => h("div", { class: "es-module" }, "ES Module Component");
|
|
30
|
+
}
|
|
31
|
+
})
|
|
32
|
+
};
|
|
33
|
+
describe("router-view.ts - RouterView Component", () => {
|
|
34
|
+
let router;
|
|
35
|
+
let testContainer;
|
|
36
|
+
beforeEach(async () => {
|
|
37
|
+
testContainer = document.createElement("div");
|
|
38
|
+
testContainer.id = "test-app";
|
|
39
|
+
document.body.appendChild(testContainer);
|
|
40
|
+
const routes = [
|
|
41
|
+
{
|
|
42
|
+
path: "/",
|
|
43
|
+
component: HomeComponent,
|
|
44
|
+
meta: { title: "Home" }
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
path: "/about",
|
|
48
|
+
component: AboutComponent,
|
|
49
|
+
meta: { title: "About" }
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
path: "/users/:id",
|
|
53
|
+
component: UserComponent,
|
|
54
|
+
meta: { title: "User" }
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
path: "/es-module",
|
|
58
|
+
component: ESModuleComponent,
|
|
59
|
+
meta: { title: "ES Module" }
|
|
60
|
+
}
|
|
61
|
+
];
|
|
62
|
+
router = new Router({
|
|
63
|
+
root: "#test-app",
|
|
64
|
+
routes,
|
|
65
|
+
mode: RouterMode.memory,
|
|
66
|
+
base: new URL("http://localhost:3000/")
|
|
67
|
+
});
|
|
68
|
+
await router.replace("/");
|
|
69
|
+
await new Promise((resolve) => setTimeout(resolve, 10));
|
|
70
|
+
});
|
|
71
|
+
afterEach(() => {
|
|
72
|
+
if (testContainer.parentNode) {
|
|
73
|
+
testContainer.parentNode.removeChild(testContainer);
|
|
74
|
+
}
|
|
75
|
+
if (router) {
|
|
76
|
+
router.destroy();
|
|
77
|
+
}
|
|
78
|
+
});
|
|
79
|
+
describe("Basic Functionality", () => {
|
|
80
|
+
it("should render matched route component at depth 0", async () => {
|
|
81
|
+
const TestApp = defineComponent({
|
|
82
|
+
setup() {
|
|
83
|
+
useProvideRouter(router);
|
|
84
|
+
return () => h("div", [h(RouterView)]);
|
|
85
|
+
}
|
|
86
|
+
});
|
|
87
|
+
const app = createApp(TestApp);
|
|
88
|
+
app.mount(testContainer);
|
|
89
|
+
await nextTick();
|
|
90
|
+
expect(testContainer.textContent).toContain("Home Page");
|
|
91
|
+
app.unmount();
|
|
92
|
+
});
|
|
93
|
+
it("should render different components when route changes", async () => {
|
|
94
|
+
const TestApp = defineComponent({
|
|
95
|
+
setup() {
|
|
96
|
+
useProvideRouter(router);
|
|
97
|
+
return () => h("div", [h(RouterView)]);
|
|
98
|
+
}
|
|
99
|
+
});
|
|
100
|
+
const app = createApp(TestApp);
|
|
101
|
+
app.mount(testContainer);
|
|
102
|
+
await nextTick();
|
|
103
|
+
expect(testContainer.textContent).toContain("Home Page");
|
|
104
|
+
await router.push("/about");
|
|
105
|
+
await nextTick();
|
|
106
|
+
expect(testContainer.textContent).toContain("About Page");
|
|
107
|
+
app.unmount();
|
|
108
|
+
});
|
|
109
|
+
it("should handle routes with parameters", async () => {
|
|
110
|
+
const TestApp = defineComponent({
|
|
111
|
+
setup() {
|
|
112
|
+
useProvideRouter(router);
|
|
113
|
+
return () => h("div", [h(RouterView)]);
|
|
114
|
+
}
|
|
115
|
+
});
|
|
116
|
+
const app = createApp(TestApp);
|
|
117
|
+
app.mount(testContainer);
|
|
118
|
+
await router.push("/users/123");
|
|
119
|
+
await nextTick();
|
|
120
|
+
expect(testContainer.textContent).toContain("User Component");
|
|
121
|
+
app.unmount();
|
|
122
|
+
});
|
|
123
|
+
});
|
|
124
|
+
describe("Component Resolution", () => {
|
|
125
|
+
it("should resolve ES module components correctly", async () => {
|
|
126
|
+
const TestApp = defineComponent({
|
|
127
|
+
setup() {
|
|
128
|
+
useProvideRouter(router);
|
|
129
|
+
return () => h("div", [h(RouterView)]);
|
|
130
|
+
}
|
|
131
|
+
});
|
|
132
|
+
const app = createApp(TestApp);
|
|
133
|
+
app.mount(testContainer);
|
|
134
|
+
await router.push("/es-module");
|
|
135
|
+
await nextTick();
|
|
136
|
+
expect(testContainer.textContent).toContain("ES Module Component");
|
|
137
|
+
app.unmount();
|
|
138
|
+
});
|
|
139
|
+
it("should handle function components", async () => {
|
|
140
|
+
const FunctionComponent = () => h("div", "Function Component");
|
|
141
|
+
const routes = [
|
|
142
|
+
{
|
|
143
|
+
path: "/function",
|
|
144
|
+
component: FunctionComponent,
|
|
145
|
+
meta: { title: "Function" }
|
|
146
|
+
}
|
|
147
|
+
];
|
|
148
|
+
const functionRouter = new Router({
|
|
149
|
+
root: "#test-app",
|
|
150
|
+
routes,
|
|
151
|
+
mode: RouterMode.memory,
|
|
152
|
+
base: new URL("http://localhost:3000/")
|
|
153
|
+
});
|
|
154
|
+
await functionRouter.replace("/function");
|
|
155
|
+
await new Promise((resolve) => setTimeout(resolve, 10));
|
|
156
|
+
const TestApp = defineComponent({
|
|
157
|
+
setup() {
|
|
158
|
+
useProvideRouter(functionRouter);
|
|
159
|
+
return () => h("div", [h(RouterView)]);
|
|
160
|
+
}
|
|
161
|
+
});
|
|
162
|
+
const app = createApp(TestApp);
|
|
163
|
+
app.mount(testContainer);
|
|
164
|
+
await nextTick();
|
|
165
|
+
expect(testContainer.textContent).toContain("Function Component");
|
|
166
|
+
app.unmount();
|
|
167
|
+
functionRouter.destroy();
|
|
168
|
+
});
|
|
169
|
+
});
|
|
170
|
+
describe("Depth Tracking", () => {
|
|
171
|
+
it("should inject depth 0 by default", async () => {
|
|
172
|
+
let injectedDepth;
|
|
173
|
+
const RouterViewDepthKey = Symbol("RouterViewDepth");
|
|
174
|
+
const TestRouterView = defineComponent({
|
|
175
|
+
name: "TestRouterView",
|
|
176
|
+
setup() {
|
|
177
|
+
injectedDepth = inject(RouterViewDepthKey, -1);
|
|
178
|
+
return () => h(RouterView);
|
|
179
|
+
}
|
|
180
|
+
});
|
|
181
|
+
const TestApp = defineComponent({
|
|
182
|
+
setup() {
|
|
183
|
+
useProvideRouter(router);
|
|
184
|
+
return () => h("div", [h(TestRouterView)]);
|
|
185
|
+
}
|
|
186
|
+
});
|
|
187
|
+
const app = createApp(TestApp);
|
|
188
|
+
app.mount(testContainer);
|
|
189
|
+
await nextTick();
|
|
190
|
+
expect(injectedDepth).toBe(-1);
|
|
191
|
+
app.unmount();
|
|
192
|
+
});
|
|
193
|
+
it("should provide correct depth in nested RouterViews", async () => {
|
|
194
|
+
let parentDepth;
|
|
195
|
+
let childDepth;
|
|
196
|
+
const RouterViewDepthKey = Symbol("RouterViewDepth");
|
|
197
|
+
const ParentTestComponent = defineComponent({
|
|
198
|
+
name: "ParentTestComponent",
|
|
199
|
+
setup() {
|
|
200
|
+
parentDepth = inject(RouterViewDepthKey, -1);
|
|
201
|
+
provide(RouterViewDepthKey, 0);
|
|
202
|
+
return () => h("div", [h("span", "Parent"), h(ChildTestComponent)]);
|
|
203
|
+
}
|
|
204
|
+
});
|
|
205
|
+
const ChildTestComponent = defineComponent({
|
|
206
|
+
name: "ChildTestComponent",
|
|
207
|
+
setup() {
|
|
208
|
+
childDepth = inject(RouterViewDepthKey, -1);
|
|
209
|
+
return () => h("div", "Child");
|
|
210
|
+
}
|
|
211
|
+
});
|
|
212
|
+
const TestApp = defineComponent({
|
|
213
|
+
setup() {
|
|
214
|
+
useProvideRouter(router);
|
|
215
|
+
return () => h("div", [h(ParentTestComponent)]);
|
|
216
|
+
}
|
|
217
|
+
});
|
|
218
|
+
const app = createApp(TestApp);
|
|
219
|
+
app.mount(testContainer);
|
|
220
|
+
await nextTick();
|
|
221
|
+
expect(parentDepth).toBe(-1);
|
|
222
|
+
expect(childDepth).toBe(0);
|
|
223
|
+
app.unmount();
|
|
224
|
+
});
|
|
225
|
+
it("should handle nested RouterViews with correct depth", async () => {
|
|
226
|
+
const Level1Component = defineComponent({
|
|
227
|
+
name: "Level1Component",
|
|
228
|
+
setup() {
|
|
229
|
+
return () => h("div", [h("span", "Level 1"), h(RouterView)]);
|
|
230
|
+
}
|
|
231
|
+
});
|
|
232
|
+
const Level2Component = defineComponent({
|
|
233
|
+
name: "Level2Component",
|
|
234
|
+
setup() {
|
|
235
|
+
return () => h("div", "Level 2");
|
|
236
|
+
}
|
|
237
|
+
});
|
|
238
|
+
const nestedRoutes = [
|
|
239
|
+
{
|
|
240
|
+
path: "/level1",
|
|
241
|
+
component: Level1Component,
|
|
242
|
+
children: [
|
|
243
|
+
{
|
|
244
|
+
path: "level2",
|
|
245
|
+
component: Level2Component
|
|
246
|
+
}
|
|
247
|
+
]
|
|
248
|
+
}
|
|
249
|
+
];
|
|
250
|
+
const nestedRouter = new Router({
|
|
251
|
+
root: "#test-app",
|
|
252
|
+
routes: nestedRoutes,
|
|
253
|
+
mode: RouterMode.memory,
|
|
254
|
+
base: new URL("http://localhost:3000/")
|
|
255
|
+
});
|
|
256
|
+
await nestedRouter.replace("/level1/level2");
|
|
257
|
+
await new Promise((resolve) => setTimeout(resolve, 10));
|
|
258
|
+
const TestApp = defineComponent({
|
|
259
|
+
setup() {
|
|
260
|
+
useProvideRouter(nestedRouter);
|
|
261
|
+
return () => h("div", [h(RouterView)]);
|
|
262
|
+
}
|
|
263
|
+
});
|
|
264
|
+
const app = createApp(TestApp);
|
|
265
|
+
app.mount(testContainer);
|
|
266
|
+
await nextTick();
|
|
267
|
+
expect(testContainer.textContent).toContain("Level 1");
|
|
268
|
+
expect(testContainer.textContent).toContain("Level 2");
|
|
269
|
+
app.unmount();
|
|
270
|
+
nestedRouter.destroy();
|
|
271
|
+
});
|
|
272
|
+
});
|
|
273
|
+
describe("Edge Cases and Error Handling", () => {
|
|
274
|
+
it("should render null when no route matches at current depth", async () => {
|
|
275
|
+
const RouterViewDepthKey = Symbol("RouterViewDepth");
|
|
276
|
+
const DeepRouterView = defineComponent({
|
|
277
|
+
name: "DeepRouterView",
|
|
278
|
+
setup() {
|
|
279
|
+
const currentDepth = inject(RouterViewDepthKey, 0);
|
|
280
|
+
provide(RouterViewDepthKey, currentDepth + 1);
|
|
281
|
+
return () => h(RouterView);
|
|
282
|
+
}
|
|
283
|
+
});
|
|
284
|
+
const TestApp = defineComponent({
|
|
285
|
+
setup() {
|
|
286
|
+
useProvideRouter(router);
|
|
287
|
+
return () => h("div", [
|
|
288
|
+
h("span", "App"),
|
|
289
|
+
h(RouterView),
|
|
290
|
+
// This renders Home component at depth 0
|
|
291
|
+
h(DeepRouterView)
|
|
292
|
+
// This tries to render at depth 1, but no match
|
|
293
|
+
]);
|
|
294
|
+
}
|
|
295
|
+
});
|
|
296
|
+
const app = createApp(TestApp);
|
|
297
|
+
app.mount(testContainer);
|
|
298
|
+
await nextTick();
|
|
299
|
+
expect(testContainer.textContent).toContain("App");
|
|
300
|
+
expect(testContainer.textContent).toContain("Home Page");
|
|
301
|
+
app.unmount();
|
|
302
|
+
});
|
|
303
|
+
it("should handle null components gracefully", async () => {
|
|
304
|
+
var _a, _b, _c;
|
|
305
|
+
const routesWithNull = [
|
|
306
|
+
{
|
|
307
|
+
path: "/null-component",
|
|
308
|
+
component: null,
|
|
309
|
+
meta: { title: "Null Component" }
|
|
310
|
+
}
|
|
311
|
+
];
|
|
312
|
+
const nullRouter = new Router({
|
|
313
|
+
root: "#test-app",
|
|
314
|
+
routes: routesWithNull,
|
|
315
|
+
mode: RouterMode.memory,
|
|
316
|
+
base: new URL("http://localhost:3000/")
|
|
317
|
+
});
|
|
318
|
+
await nullRouter.replace("/null-component");
|
|
319
|
+
await new Promise((resolve) => setTimeout(resolve, 10));
|
|
320
|
+
const TestApp = defineComponent({
|
|
321
|
+
setup() {
|
|
322
|
+
useProvideRouter(nullRouter);
|
|
323
|
+
return () => h("div", [h("span", "App"), h(RouterView)]);
|
|
324
|
+
}
|
|
325
|
+
});
|
|
326
|
+
const app = createApp(TestApp);
|
|
327
|
+
app.mount(testContainer);
|
|
328
|
+
await nextTick();
|
|
329
|
+
expect((_a = testContainer.textContent) == null ? void 0 : _a.trim()).toBe("App");
|
|
330
|
+
expect((_b = testContainer.querySelector("div")) == null ? void 0 : _b.children.length).toBe(1);
|
|
331
|
+
expect((_c = testContainer.querySelector("span")) == null ? void 0 : _c.textContent).toBe(
|
|
332
|
+
"App"
|
|
333
|
+
);
|
|
334
|
+
app.unmount();
|
|
335
|
+
nullRouter.destroy();
|
|
336
|
+
});
|
|
337
|
+
it("should handle non-existent routes", async () => {
|
|
338
|
+
var _a, _b, _c;
|
|
339
|
+
const nonExistentRouter = new Router({
|
|
340
|
+
root: "#test-app",
|
|
341
|
+
routes: [
|
|
342
|
+
{
|
|
343
|
+
path: "/",
|
|
344
|
+
component: null
|
|
345
|
+
// Initial route with null component
|
|
346
|
+
}
|
|
347
|
+
],
|
|
348
|
+
mode: RouterMode.memory,
|
|
349
|
+
base: new URL("http://localhost:3000/")
|
|
350
|
+
});
|
|
351
|
+
await nonExistentRouter.replace("/");
|
|
352
|
+
await new Promise((resolve) => setTimeout(resolve, 10));
|
|
353
|
+
const TestApp = defineComponent({
|
|
354
|
+
setup() {
|
|
355
|
+
useProvideRouter(nonExistentRouter);
|
|
356
|
+
return () => h("div", [h("span", "App"), h(RouterView)]);
|
|
357
|
+
}
|
|
358
|
+
});
|
|
359
|
+
const app = createApp(TestApp);
|
|
360
|
+
app.mount(testContainer);
|
|
361
|
+
await nonExistentRouter.push("/non-existent");
|
|
362
|
+
await nextTick();
|
|
363
|
+
await new Promise((resolve) => setTimeout(resolve, 10));
|
|
364
|
+
expect((_a = testContainer.textContent) == null ? void 0 : _a.trim()).toBe("App");
|
|
365
|
+
expect((_b = testContainer.querySelector("div")) == null ? void 0 : _b.children.length).toBe(1);
|
|
366
|
+
expect((_c = testContainer.querySelector("span")) == null ? void 0 : _c.textContent).toBe(
|
|
367
|
+
"App"
|
|
368
|
+
);
|
|
369
|
+
app.unmount();
|
|
370
|
+
nonExistentRouter.destroy();
|
|
371
|
+
});
|
|
372
|
+
it("should handle malformed ES modules", async () => {
|
|
373
|
+
const MalformedModule = {
|
|
374
|
+
__esModule: true,
|
|
375
|
+
default: null
|
|
376
|
+
};
|
|
377
|
+
const malformedRoutes = [
|
|
378
|
+
{
|
|
379
|
+
path: "/malformed",
|
|
380
|
+
component: MalformedModule,
|
|
381
|
+
meta: { title: "Malformed" }
|
|
382
|
+
}
|
|
383
|
+
];
|
|
384
|
+
const malformedRouter = new Router({
|
|
385
|
+
root: "#test-app",
|
|
386
|
+
routes: malformedRoutes,
|
|
387
|
+
mode: RouterMode.memory,
|
|
388
|
+
base: new URL("http://localhost:3000/")
|
|
389
|
+
});
|
|
390
|
+
await malformedRouter.replace("/malformed");
|
|
391
|
+
await new Promise((resolve) => setTimeout(resolve, 10));
|
|
392
|
+
const TestApp = defineComponent({
|
|
393
|
+
setup() {
|
|
394
|
+
useProvideRouter(malformedRouter);
|
|
395
|
+
return () => h("div", [h("span", "App"), h(RouterView)]);
|
|
396
|
+
}
|
|
397
|
+
});
|
|
398
|
+
const app = createApp(TestApp);
|
|
399
|
+
app.mount(testContainer);
|
|
400
|
+
await nextTick();
|
|
401
|
+
expect(testContainer.textContent).toBe("App");
|
|
402
|
+
app.unmount();
|
|
403
|
+
malformedRouter.destroy();
|
|
404
|
+
});
|
|
405
|
+
});
|
|
406
|
+
describe("Component Properties", () => {
|
|
407
|
+
it("should have correct component name", () => {
|
|
408
|
+
expect(RouterView.name).toBe("RouterView");
|
|
409
|
+
});
|
|
410
|
+
it("should be a valid Vue component", () => {
|
|
411
|
+
expect(RouterView).toHaveProperty("setup");
|
|
412
|
+
expect(typeof RouterView.setup).toBe("function");
|
|
413
|
+
});
|
|
414
|
+
it("should not define props", () => {
|
|
415
|
+
expect(RouterView.props).toBeUndefined();
|
|
416
|
+
});
|
|
417
|
+
});
|
|
418
|
+
describe("Integration Tests", () => {
|
|
419
|
+
it("should re-render when route changes", async () => {
|
|
420
|
+
const TestApp = defineComponent({
|
|
421
|
+
setup() {
|
|
422
|
+
useProvideRouter(router);
|
|
423
|
+
return () => h("div", [h(RouterView)]);
|
|
424
|
+
}
|
|
425
|
+
});
|
|
426
|
+
const app = createApp(TestApp);
|
|
427
|
+
app.mount(testContainer);
|
|
428
|
+
await nextTick();
|
|
429
|
+
expect(testContainer.textContent).toContain("Home Page");
|
|
430
|
+
await router.push("/about");
|
|
431
|
+
await nextTick();
|
|
432
|
+
expect(testContainer.textContent).toContain("About Page");
|
|
433
|
+
await router.push("/users/123");
|
|
434
|
+
await nextTick();
|
|
435
|
+
expect(testContainer.textContent).toContain("User Component");
|
|
436
|
+
app.unmount();
|
|
437
|
+
});
|
|
438
|
+
it("should work with router navigation methods", async () => {
|
|
439
|
+
const TestApp = defineComponent({
|
|
440
|
+
setup() {
|
|
441
|
+
useProvideRouter(router);
|
|
442
|
+
return () => h("div", [h(RouterView)]);
|
|
443
|
+
}
|
|
444
|
+
});
|
|
445
|
+
const app = createApp(TestApp);
|
|
446
|
+
app.mount(testContainer);
|
|
447
|
+
await router.push("/about");
|
|
448
|
+
await nextTick();
|
|
449
|
+
expect(testContainer.textContent).toContain("About Page");
|
|
450
|
+
await router.replace("/users/456");
|
|
451
|
+
await nextTick();
|
|
452
|
+
expect(testContainer.textContent).toContain("User Component");
|
|
453
|
+
await router.back();
|
|
454
|
+
await nextTick();
|
|
455
|
+
expect(testContainer.textContent).toContain("Home Page");
|
|
456
|
+
app.unmount();
|
|
457
|
+
});
|
|
458
|
+
});
|
|
459
|
+
});
|
package/dist/use.d.ts
CHANGED
|
@@ -1,4 +1,199 @@
|
|
|
1
|
-
import type { Route,
|
|
2
|
-
export
|
|
3
|
-
|
|
1
|
+
import type { Route, Router, RouterLinkProps } from '@esmx/router';
|
|
2
|
+
export interface VueInstance {
|
|
3
|
+
$parent?: VueInstance | null;
|
|
4
|
+
$root?: VueInstance | null;
|
|
5
|
+
$children?: VueInstance[] | null;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Get router instance from a Vue component instance.
|
|
9
|
+
* This is a lower-level function used internally by useRouter().
|
|
10
|
+
* Use this in Options API, use useRouter() in Composition API.
|
|
11
|
+
*
|
|
12
|
+
* @param instance - Vue component instance (optional, will use getCurrentInstance if not provided)
|
|
13
|
+
* @returns Router instance
|
|
14
|
+
* @throws {Error} If router context is not found
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* ```typescript
|
|
18
|
+
* // Options API usage
|
|
19
|
+
* import { defineComponent } from 'vue';
|
|
20
|
+
* import { getRouter } from '@esmx/router-vue';
|
|
21
|
+
*
|
|
22
|
+
* export default defineComponent({
|
|
23
|
+
* mounted() {
|
|
24
|
+
* const router = getRouter(this);
|
|
25
|
+
* router.push('/dashboard');
|
|
26
|
+
* },
|
|
27
|
+
* methods: {
|
|
28
|
+
* handleNavigation() {
|
|
29
|
+
* const router = getRouter(this);
|
|
30
|
+
* router.replace('/profile');
|
|
31
|
+
* }
|
|
32
|
+
* }
|
|
33
|
+
* });
|
|
34
|
+
*
|
|
35
|
+
* // Can also be called without instance (uses getCurrentInstance internally)
|
|
36
|
+
* const router = getRouter(); // Works in globalProperties getters
|
|
37
|
+
* ```
|
|
38
|
+
*/
|
|
39
|
+
export declare function getRouter(instance?: VueInstance): Router;
|
|
40
|
+
/**
|
|
41
|
+
* Get current route from a Vue component instance.
|
|
42
|
+
* This is a lower-level function used internally by useRoute().
|
|
43
|
+
* Use this in Options API, use useRoute() in Composition API.
|
|
44
|
+
*
|
|
45
|
+
* @param instance - Vue component instance (optional, will use getCurrentInstance if not provided)
|
|
46
|
+
* @returns Current route object
|
|
47
|
+
* @throws {Error} If router context is not found
|
|
48
|
+
*
|
|
49
|
+
* @example
|
|
50
|
+
* ```typescript
|
|
51
|
+
* // Options API usage
|
|
52
|
+
* import { defineComponent } from 'vue';
|
|
53
|
+
* import { getRoute } from '@esmx/router-vue';
|
|
54
|
+
*
|
|
55
|
+
* export default defineComponent({
|
|
56
|
+
* computed: {
|
|
57
|
+
* routeInfo() {
|
|
58
|
+
* const route = getRoute(this);
|
|
59
|
+
* return {
|
|
60
|
+
* path: route.path,
|
|
61
|
+
* params: route.params,
|
|
62
|
+
* query: route.query
|
|
63
|
+
* };
|
|
64
|
+
* }
|
|
65
|
+
* }
|
|
66
|
+
* });
|
|
67
|
+
*
|
|
68
|
+
* // Can also be called without instance (uses getCurrentInstance internally)
|
|
69
|
+
* const route = getRoute(); // Works in globalProperties getters
|
|
70
|
+
* ```
|
|
71
|
+
*/
|
|
72
|
+
export declare function getRoute(instance?: VueInstance): Route;
|
|
73
|
+
/**
|
|
74
|
+
* Get the router instance in a Vue component.
|
|
75
|
+
* Must be called within setup() or other composition functions.
|
|
76
|
+
* Use this in Composition API, use getRouter() in Options API.
|
|
77
|
+
*
|
|
78
|
+
* @returns Router instance for navigation and route management
|
|
79
|
+
* @throws {Error} If called outside setup() or router context not found
|
|
80
|
+
*
|
|
81
|
+
* @example
|
|
82
|
+
* ```vue
|
|
83
|
+
* <script setup lang="ts">
|
|
84
|
+
* import { useRouter } from '@esmx/router-vue';
|
|
85
|
+
*
|
|
86
|
+
* const router = useRouter();
|
|
87
|
+
*
|
|
88
|
+
* const navigateToHome = () => {
|
|
89
|
+
* router.push('/home');
|
|
90
|
+
* };
|
|
91
|
+
*
|
|
92
|
+
* const goBack = () => {
|
|
93
|
+
* router.back();
|
|
94
|
+
* };
|
|
95
|
+
*
|
|
96
|
+
* const navigateWithQuery = () => {
|
|
97
|
+
* router.push({
|
|
98
|
+
* path: '/search',
|
|
99
|
+
* query: { q: 'vue router', page: '1' }
|
|
100
|
+
* });
|
|
101
|
+
* };
|
|
102
|
+
* </script>
|
|
103
|
+
* ```
|
|
104
|
+
*/
|
|
105
|
+
export declare function useRouter(): Router;
|
|
106
|
+
/**
|
|
107
|
+
* Get the current route information in a Vue component.
|
|
108
|
+
* Returns a reactive reference that automatically updates when the route changes.
|
|
109
|
+
* Must be called within setup() or other composition functions.
|
|
110
|
+
* Use this in Composition API, use getRoute() in Options API.
|
|
111
|
+
*
|
|
112
|
+
* @returns Current route object with path, params, query, etc.
|
|
113
|
+
* @throws {Error} If called outside setup() or router context not found
|
|
114
|
+
*
|
|
115
|
+
* @example
|
|
116
|
+
* ```vue
|
|
117
|
+
* <template>
|
|
118
|
+
* <div>
|
|
119
|
+
* <h1>{{ route.meta?.title || 'Page' }}</h1>
|
|
120
|
+
* <p>Path: {{ route.path }}</p>
|
|
121
|
+
* <p>Params: {{ JSON.stringify(route.params) }}</p>
|
|
122
|
+
* <p>Query: {{ JSON.stringify(route.query) }}</p>
|
|
123
|
+
* </div>
|
|
124
|
+
* </template>
|
|
125
|
+
*
|
|
126
|
+
* <script setup lang="ts">
|
|
127
|
+
* import { useRoute } from '@esmx/router-vue';
|
|
128
|
+
* import { watch } from 'vue';
|
|
129
|
+
*
|
|
130
|
+
* const route = useRoute();
|
|
131
|
+
*
|
|
132
|
+
* watch(() => route.path, (newPath) => {
|
|
133
|
+
* console.log('Route changed to:', newPath);
|
|
134
|
+
* });
|
|
135
|
+
* </script>
|
|
136
|
+
* ```
|
|
137
|
+
*/
|
|
4
138
|
export declare function useRoute(): Route;
|
|
139
|
+
/**
|
|
140
|
+
* Provide router context to child components.
|
|
141
|
+
* This must be called in a parent component to make the router available
|
|
142
|
+
* to child components via useRouter() and useRoute().
|
|
143
|
+
*
|
|
144
|
+
* @param router - Router instance to provide to child components
|
|
145
|
+
* @throws {Error} If called outside setup()
|
|
146
|
+
*
|
|
147
|
+
* @example
|
|
148
|
+
* ```typescript
|
|
149
|
+
* // Vue 3 usage
|
|
150
|
+
* import { createApp } from 'vue';
|
|
151
|
+
* import { Router } from '@esmx/router';
|
|
152
|
+
* import { useProvideRouter } from '@esmx/router-vue';
|
|
153
|
+
*
|
|
154
|
+
* const routes = [
|
|
155
|
+
* { path: '/', component: () => import('./Home.vue') },
|
|
156
|
+
* { path: '/about', component: () => import('./About.vue') }
|
|
157
|
+
* ];
|
|
158
|
+
*
|
|
159
|
+
* const router = new Router({ routes });
|
|
160
|
+
* const app = createApp({
|
|
161
|
+
* setup() {
|
|
162
|
+
* useProvideRouter(router);
|
|
163
|
+
* }
|
|
164
|
+
* });
|
|
165
|
+
* app.mount('#app');
|
|
166
|
+
* ```
|
|
167
|
+
*/
|
|
168
|
+
export declare function useProvideRouter(router: Router): void;
|
|
169
|
+
/**
|
|
170
|
+
* Create reactive link helpers for navigation elements.
|
|
171
|
+
* Returns computed properties for link attributes, classes, and event handlers.
|
|
172
|
+
*
|
|
173
|
+
* @param props - RouterLink properties configuration
|
|
174
|
+
* @returns Computed link resolver with attributes and event handlers
|
|
175
|
+
*
|
|
176
|
+
* @example
|
|
177
|
+
* ```vue
|
|
178
|
+
* <template>
|
|
179
|
+
* <a
|
|
180
|
+
* v-bind="link.attributes"
|
|
181
|
+
* v-on="link.getEventHandlers()"
|
|
182
|
+
* :class="{ active: link.isActive }"
|
|
183
|
+
* >
|
|
184
|
+
* Home
|
|
185
|
+
* </a>
|
|
186
|
+
* </template>
|
|
187
|
+
*
|
|
188
|
+
* <script setup lang="ts">
|
|
189
|
+
* import { useLink } from '@esmx/router-vue';
|
|
190
|
+
*
|
|
191
|
+
* const link = useLink({
|
|
192
|
+
* to: '/home',
|
|
193
|
+
* type: 'push',
|
|
194
|
+
* exact: 'include'
|
|
195
|
+
* }).value;
|
|
196
|
+
* </script>
|
|
197
|
+
* ```
|
|
198
|
+
*/
|
|
199
|
+
export declare function useLink(props: RouterLinkProps): import("vue").ComputedRef<import("@esmx/router").RouterLinkResolved>;
|