@esmx/router 3.0.0-rc.24 → 3.0.0-rc.26
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/dist/error.mjs +14 -11
- package/dist/increment-id.mjs +6 -1
- package/dist/location.mjs +3 -2
- package/dist/location.test.mjs +7 -7
- package/dist/matcher.mjs +1 -1
- package/dist/matcher.test.mjs +5 -5
- package/dist/micro-app.mjs +9 -4
- package/dist/navigation.d.ts +3 -1
- package/dist/navigation.mjs +28 -18
- package/dist/options.mjs +13 -12
- package/dist/route-task.mjs +6 -1
- package/dist/route-transition.mjs +17 -13
- package/dist/route-transition.test.mjs +1 -1
- package/dist/route.mjs +31 -28
- package/dist/route.test.mjs +4 -4
- package/dist/router-back.test.mjs +1 -1
- package/dist/router-forward.test.mjs +1 -1
- package/dist/router-link.mjs +12 -7
- package/dist/router-restart-app.dom.test.mjs +6 -6
- package/dist/router-window-navigation.test.mjs +32 -32
- package/dist/router.mjs +49 -31
- package/dist/types.d.ts +4 -2
- package/dist/util.test.mjs +18 -18
- package/package.json +8 -8
- package/src/navigation.ts +9 -2
- package/src/route-transition.ts +1 -1
- package/src/router-link.ts +20 -17
- package/src/router.ts +15 -3
- package/src/types.ts +7 -2
package/dist/router-link.mjs
CHANGED
|
@@ -18,9 +18,13 @@ function getEventTypeList(eventType) {
|
|
|
18
18
|
return validEvents.length ? validEvents : ["click"];
|
|
19
19
|
}
|
|
20
20
|
function guardEvent(e) {
|
|
21
|
-
|
|
22
|
-
if (e
|
|
23
|
-
if (e.
|
|
21
|
+
var _a, _b, _c;
|
|
22
|
+
if (!e) return;
|
|
23
|
+
if (e.metaKey || e.altKey || e.ctrlKey || e.shiftKey) return;
|
|
24
|
+
if (e.defaultPrevented) return;
|
|
25
|
+
if (e.button !== void 0 && e.button !== 0) return;
|
|
26
|
+
const target = (_c = (_b = (_a = e.currentTarget) == null ? void 0 : _a.getAttribute) == null ? void 0 : _b.call(_a, "target")) != null ? _c : "";
|
|
27
|
+
if (/\b_blank\b/i.test(target)) return;
|
|
24
28
|
if (e.preventDefault) e.preventDefault();
|
|
25
29
|
return true;
|
|
26
30
|
}
|
|
@@ -50,9 +54,9 @@ async function executeNavigation(router, props, linkType) {
|
|
|
50
54
|
}
|
|
51
55
|
function createNavigateFunction(router, props, navigationType) {
|
|
52
56
|
return async (e) => {
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
57
|
+
var _a;
|
|
58
|
+
const eventHandler = (_a = props.eventHandler) != null ? _a : guardEvent;
|
|
59
|
+
if (!eventHandler(e)) return;
|
|
56
60
|
await executeNavigation(router, props, navigationType);
|
|
57
61
|
};
|
|
58
62
|
}
|
|
@@ -88,7 +92,8 @@ function createEventHandlersGenerator(navigate, eventTypes) {
|
|
|
88
92
|
return (nameTransform) => {
|
|
89
93
|
const handlers = {};
|
|
90
94
|
eventTypes.forEach((eventType) => {
|
|
91
|
-
|
|
95
|
+
var _a;
|
|
96
|
+
const eventName = (_a = nameTransform == null ? void 0 : nameTransform(eventType)) != null ? _a : eventType.toLowerCase();
|
|
92
97
|
handlers[eventName] = navigate;
|
|
93
98
|
});
|
|
94
99
|
return handlers;
|
|
@@ -246,7 +246,7 @@ describe("Router.restartApp Focused Tests", () => {
|
|
|
246
246
|
it("should correctly execute beforeEach guards", async () => {
|
|
247
247
|
const unregister = router.beforeEach(async (to, from) => {
|
|
248
248
|
guardExecutionLog.push(
|
|
249
|
-
|
|
249
|
+
"beforeEach-".concat(to.path, "-from-").concat((from == null ? void 0 : from.path) || "null")
|
|
250
250
|
);
|
|
251
251
|
});
|
|
252
252
|
await router.restartApp("/about");
|
|
@@ -256,7 +256,7 @@ describe("Router.restartApp Focused Tests", () => {
|
|
|
256
256
|
it("should correctly execute afterEach guards", async () => {
|
|
257
257
|
const unregister = router.afterEach((to, from) => {
|
|
258
258
|
guardExecutionLog.push(
|
|
259
|
-
|
|
259
|
+
"afterEach-".concat(to.path, "-from-").concat((from == null ? void 0 : from.path) || "null")
|
|
260
260
|
);
|
|
261
261
|
});
|
|
262
262
|
await router.restartApp("/about");
|
|
@@ -504,10 +504,10 @@ describe("Router.restartApp Focused Tests", () => {
|
|
|
504
504
|
});
|
|
505
505
|
it("should correctly execute complete route lifecycle", async () => {
|
|
506
506
|
const unregisterBefore = lifecycleRouter.beforeEach((to, from) => {
|
|
507
|
-
lifecycleLog.push(
|
|
507
|
+
lifecycleLog.push("global-beforeEach-".concat(to.path));
|
|
508
508
|
});
|
|
509
509
|
const unregisterAfter = lifecycleRouter.afterEach((to, from) => {
|
|
510
|
-
lifecycleLog.push(
|
|
510
|
+
lifecycleLog.push("global-afterEach-".concat(to.path));
|
|
511
511
|
});
|
|
512
512
|
await lifecycleRouter.restartApp("/lifecycle");
|
|
513
513
|
expect(lifecycleLog).toEqual([
|
|
@@ -588,7 +588,7 @@ describe("Router.restartApp Focused Tests", () => {
|
|
|
588
588
|
0
|
|
589
589
|
);
|
|
590
590
|
for (let i = 0; i < 50; i++) {
|
|
591
|
-
await router.restartApp(
|
|
591
|
+
await router.restartApp("/user/".concat(i));
|
|
592
592
|
}
|
|
593
593
|
const finalAppsCallCount = Object.values(mockApps).reduce(
|
|
594
594
|
(sum, app) => sum + app.mock.calls.length,
|
|
@@ -601,7 +601,7 @@ describe("Router.restartApp Focused Tests", () => {
|
|
|
601
601
|
const startTime = Date.now();
|
|
602
602
|
const promises = Array.from(
|
|
603
603
|
{ length: 10 },
|
|
604
|
-
(_, i) => router.restartApp(
|
|
604
|
+
(_, i) => router.restartApp("/user/".concat(i)).catch((err) => err)
|
|
605
605
|
);
|
|
606
606
|
const results = await Promise.all(promises);
|
|
607
607
|
const endTime = Date.now();
|
|
@@ -33,8 +33,8 @@ describe("Router Window Navigation Tests", () => {
|
|
|
33
33
|
});
|
|
34
34
|
});
|
|
35
35
|
function createWindowNavigationTests(methodName, expectedIsPush) {
|
|
36
|
-
describe(
|
|
37
|
-
it(
|
|
36
|
+
describe("\u{1FA9F} ".concat(methodName, " Core Functionality Tests"), () => {
|
|
37
|
+
it("should support using current route path", async () => {
|
|
38
38
|
await router.push("/about");
|
|
39
39
|
const result = await router[methodName]("/about");
|
|
40
40
|
expect(result.type).toBe(RouteType[methodName]);
|
|
@@ -42,7 +42,7 @@ describe("Router Window Navigation Tests", () => {
|
|
|
42
42
|
expect(result.isPush).toBe(expectedIsPush);
|
|
43
43
|
expect(result.handle).not.toBeNull();
|
|
44
44
|
});
|
|
45
|
-
it(
|
|
45
|
+
it("should support string path parameters", async () => {
|
|
46
46
|
const result = await router[methodName]("/user/123");
|
|
47
47
|
expect(result.type).toBe(RouteType[methodName]);
|
|
48
48
|
expect(result.path).toBe("/user/123");
|
|
@@ -50,7 +50,7 @@ describe("Router Window Navigation Tests", () => {
|
|
|
50
50
|
expect(result.isPush).toBe(expectedIsPush);
|
|
51
51
|
expect(result.handle).not.toBeNull();
|
|
52
52
|
});
|
|
53
|
-
it(
|
|
53
|
+
it("should support object parameters", async () => {
|
|
54
54
|
const result = await router[methodName]({
|
|
55
55
|
path: "/user/456",
|
|
56
56
|
query: { tab: "profile" },
|
|
@@ -64,7 +64,7 @@ describe("Router Window Navigation Tests", () => {
|
|
|
64
64
|
expect(result.isPush).toBe(expectedIsPush);
|
|
65
65
|
expect(result.handle).not.toBeNull();
|
|
66
66
|
});
|
|
67
|
-
it(
|
|
67
|
+
it("should correctly handle complete URLs", async () => {
|
|
68
68
|
const result = await router[methodName](
|
|
69
69
|
"https://example.com/user/789?sort=name#top"
|
|
70
70
|
);
|
|
@@ -76,13 +76,13 @@ describe("Router Window Navigation Tests", () => {
|
|
|
76
76
|
expect(result.handle).not.toBeNull();
|
|
77
77
|
});
|
|
78
78
|
});
|
|
79
|
-
describe(
|
|
80
|
-
it(
|
|
79
|
+
describe("\u{1F3AF} ".concat(methodName, " Specific Behavior Tests"), () => {
|
|
80
|
+
it("should set correct isPush flag", async () => {
|
|
81
81
|
const result = await router[methodName]("/about");
|
|
82
82
|
expect(result.isPush).toBe(expectedIsPush);
|
|
83
83
|
expect(result.type).toBe(RouteType[methodName]);
|
|
84
84
|
});
|
|
85
|
-
it(
|
|
85
|
+
it("should call location handler", async () => {
|
|
86
86
|
let locationCalled = false;
|
|
87
87
|
let receivedRoute = null;
|
|
88
88
|
const windowRouter = new Router({
|
|
@@ -101,7 +101,7 @@ describe("Router Window Navigation Tests", () => {
|
|
|
101
101
|
expect(result.handleResult).toEqual({ windowNavigation: true });
|
|
102
102
|
windowRouter.destroy();
|
|
103
103
|
});
|
|
104
|
-
it(
|
|
104
|
+
it("should not update current route state", async () => {
|
|
105
105
|
await router.push("/about");
|
|
106
106
|
const beforeRoute = router.route;
|
|
107
107
|
await router[methodName]("/user/123");
|
|
@@ -109,14 +109,14 @@ describe("Router Window Navigation Tests", () => {
|
|
|
109
109
|
expect(afterRoute.path).toBe(beforeRoute.path);
|
|
110
110
|
expect(afterRoute.url.href).toBe(beforeRoute.url.href);
|
|
111
111
|
});
|
|
112
|
-
it(
|
|
112
|
+
it("should not trigger MicroApp update", async () => {
|
|
113
113
|
const updateSpy = vi.spyOn(router.microApp, "_update");
|
|
114
114
|
await router[methodName]("/user/123");
|
|
115
115
|
expect(updateSpy).not.toHaveBeenCalled();
|
|
116
116
|
});
|
|
117
117
|
});
|
|
118
|
-
describe(
|
|
119
|
-
it(
|
|
118
|
+
describe("\u{1F6E1}\uFE0F ".concat(methodName, " Route Guards Tests"), () => {
|
|
119
|
+
it("should execute beforeEach guards", async () => {
|
|
120
120
|
let guardCalled = false;
|
|
121
121
|
const unregister = router.beforeEach(async (to, from) => {
|
|
122
122
|
guardCalled = true;
|
|
@@ -126,7 +126,7 @@ describe("Router Window Navigation Tests", () => {
|
|
|
126
126
|
expect(guardCalled).toBe(true);
|
|
127
127
|
unregister();
|
|
128
128
|
});
|
|
129
|
-
it(
|
|
129
|
+
it("should abort navigation when guard returns false", async () => {
|
|
130
130
|
const unregister = router.beforeEach((to, from) => {
|
|
131
131
|
return false;
|
|
132
132
|
});
|
|
@@ -135,7 +135,7 @@ describe("Router Window Navigation Tests", () => {
|
|
|
135
135
|
);
|
|
136
136
|
unregister();
|
|
137
137
|
});
|
|
138
|
-
it(
|
|
138
|
+
it("should support guard redirects", async () => {
|
|
139
139
|
const unregister = router.beforeEach(async (to) => {
|
|
140
140
|
if (to.path === "/about") {
|
|
141
141
|
return "/user/redirect";
|
|
@@ -146,7 +146,7 @@ describe("Router Window Navigation Tests", () => {
|
|
|
146
146
|
expect(result.params.id).toBe("redirect");
|
|
147
147
|
unregister();
|
|
148
148
|
});
|
|
149
|
-
it(
|
|
149
|
+
it("should execute afterEach guards", async () => {
|
|
150
150
|
let guardCalled = false;
|
|
151
151
|
const unregister = router.afterEach((to, from) => {
|
|
152
152
|
guardCalled = true;
|
|
@@ -157,19 +157,19 @@ describe("Router Window Navigation Tests", () => {
|
|
|
157
157
|
unregister();
|
|
158
158
|
});
|
|
159
159
|
});
|
|
160
|
-
describe(
|
|
161
|
-
it(
|
|
160
|
+
describe("\u{1F3AD} ".concat(methodName, " Edge Cases Tests"), () => {
|
|
161
|
+
it("should handle non-existent routes", async () => {
|
|
162
162
|
const result = await router[methodName]("/nonexistent");
|
|
163
163
|
expect(result.handle).not.toBeNull();
|
|
164
164
|
expect(result.matched.length).toBe(0);
|
|
165
165
|
expect(result.isPush).toBe(expectedIsPush);
|
|
166
166
|
});
|
|
167
|
-
it(
|
|
167
|
+
it("should handle empty string path", async () => {
|
|
168
168
|
const result = await router[methodName]("");
|
|
169
169
|
expect(result.handle).not.toBeNull();
|
|
170
170
|
expect(result.isPush).toBe(expectedIsPush);
|
|
171
171
|
});
|
|
172
|
-
it(
|
|
172
|
+
it("should handle special characters", async () => {
|
|
173
173
|
const result = await router[methodName](
|
|
174
174
|
"/user/\u6D4B\u8BD5\u7528\u6237?name=\u5F20\u4E09&age=25#\u4E2A\u4EBA\u4FE1\u606F"
|
|
175
175
|
);
|
|
@@ -180,8 +180,8 @@ describe("Router Window Navigation Tests", () => {
|
|
|
180
180
|
);
|
|
181
181
|
});
|
|
182
182
|
});
|
|
183
|
-
describe(
|
|
184
|
-
it(
|
|
183
|
+
describe("\u26A1 ".concat(methodName, " Task Cancellation and Concurrency Control"), () => {
|
|
184
|
+
it("should support concurrent calls", async () => {
|
|
185
185
|
const promises = [
|
|
186
186
|
router[methodName]("/user/1").catch((err) => err),
|
|
187
187
|
router[methodName]("/user/2").catch((err) => err),
|
|
@@ -198,10 +198,10 @@ describe("Router Window Navigation Tests", () => {
|
|
|
198
198
|
expect(result.isPush).toBe(expectedIsPush);
|
|
199
199
|
});
|
|
200
200
|
});
|
|
201
|
-
it(
|
|
201
|
+
it("should correctly handle rapid consecutive calls", async () => {
|
|
202
202
|
const results = [];
|
|
203
203
|
for (let i = 0; i < 5; i++) {
|
|
204
|
-
results.push(await router[methodName](
|
|
204
|
+
results.push(await router[methodName]("/user/".concat(i)));
|
|
205
205
|
}
|
|
206
206
|
results.forEach((result, index) => {
|
|
207
207
|
expect(result.handle).not.toBeNull();
|
|
@@ -210,15 +210,15 @@ describe("Router Window Navigation Tests", () => {
|
|
|
210
210
|
});
|
|
211
211
|
});
|
|
212
212
|
});
|
|
213
|
-
describe(
|
|
214
|
-
it(
|
|
213
|
+
describe("\u274C ".concat(methodName, " Error Handling"), () => {
|
|
214
|
+
it("should handle exceptions in guards", async () => {
|
|
215
215
|
const unregister = router.beforeEach(async () => {
|
|
216
216
|
throw new Error("Guard error");
|
|
217
217
|
});
|
|
218
218
|
await expect(router[methodName]("/about")).rejects.toThrow();
|
|
219
219
|
unregister();
|
|
220
220
|
});
|
|
221
|
-
it(
|
|
221
|
+
it("should handle location handler exceptions", async () => {
|
|
222
222
|
const windowRouter = new Router({
|
|
223
223
|
routes: [{ path: "/", app: "home" }],
|
|
224
224
|
apps: mockApps,
|
|
@@ -233,8 +233,8 @@ describe("Router Window Navigation Tests", () => {
|
|
|
233
233
|
windowRouter.destroy();
|
|
234
234
|
});
|
|
235
235
|
});
|
|
236
|
-
describe(
|
|
237
|
-
it(
|
|
236
|
+
describe("\u{1F9E9} ".concat(methodName, " Async Component Handling"), () => {
|
|
237
|
+
it("should correctly handle async components", async () => {
|
|
238
238
|
const asyncRouter = new Router({
|
|
239
239
|
routes: [
|
|
240
240
|
{
|
|
@@ -261,7 +261,7 @@ describe("Router Window Navigation Tests", () => {
|
|
|
261
261
|
expect(result.handleResult).toEqual({ windowNavigation: true });
|
|
262
262
|
asyncRouter.destroy();
|
|
263
263
|
});
|
|
264
|
-
it(
|
|
264
|
+
it("should handle async component loading failures", async () => {
|
|
265
265
|
const asyncRouter = new Router({
|
|
266
266
|
routes: [
|
|
267
267
|
{
|
|
@@ -285,8 +285,8 @@ describe("Router Window Navigation Tests", () => {
|
|
|
285
285
|
asyncRouter.destroy();
|
|
286
286
|
});
|
|
287
287
|
});
|
|
288
|
-
describe(
|
|
289
|
-
it(
|
|
288
|
+
describe("\u{1F527} ".concat(methodName, " Differences from Other Methods"), () => {
|
|
289
|
+
it("should behave differently from push/replace methods", async () => {
|
|
290
290
|
await router.push("/about");
|
|
291
291
|
const pushResult = await router.push("/user/123");
|
|
292
292
|
const windowResult = await router[methodName]("/user/456");
|
|
@@ -296,7 +296,7 @@ describe("Router Window Navigation Tests", () => {
|
|
|
296
296
|
expect(pushResult.type).toBe(RouteType.push);
|
|
297
297
|
expect(windowResult.type).toBe(RouteType[methodName]);
|
|
298
298
|
});
|
|
299
|
-
it(
|
|
299
|
+
it("should maintain consistency with resolve method in URL parsing", async () => {
|
|
300
300
|
const resolvedRoute = router.resolve("/user/789");
|
|
301
301
|
const windowRoute = await router[methodName]("/user/789");
|
|
302
302
|
expect(windowRoute.url.href).toBe(resolvedRoute.url.href);
|
package/dist/router.mjs
CHANGED
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
3
|
+
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
1
4
|
import { LAYER_ID } from "./increment-id.mjs";
|
|
2
5
|
import { MicroApp } from "./micro-app.mjs";
|
|
3
6
|
import { Navigation } from "./navigation.mjs";
|
|
@@ -8,13 +11,27 @@ import { createLinkResolver } from "./router-link.mjs";
|
|
|
8
11
|
import { RouteType, RouterMode } from "./types.mjs";
|
|
9
12
|
import { isNotNullish, isPlainObject, isRouteMatched } from "./util.mjs";
|
|
10
13
|
export class Router {
|
|
11
|
-
options
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
14
|
+
constructor(options) {
|
|
15
|
+
__publicField(this, "options");
|
|
16
|
+
__publicField(this, "parsedOptions");
|
|
17
|
+
__publicField(this, "isLayer");
|
|
18
|
+
__publicField(this, "navigation");
|
|
19
|
+
__publicField(this, "microApp", new MicroApp());
|
|
20
|
+
// Route transition manager
|
|
21
|
+
__publicField(this, "transition", new RouteTransition(this));
|
|
22
|
+
this.options = options;
|
|
23
|
+
this.parsedOptions = parsedOptions(options);
|
|
24
|
+
this.isLayer = this.parsedOptions.layer;
|
|
25
|
+
this.navigation = new Navigation(
|
|
26
|
+
this.parsedOptions,
|
|
27
|
+
(url, state) => {
|
|
28
|
+
this.transition.to(RouteType.unknown, {
|
|
29
|
+
url,
|
|
30
|
+
state
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
);
|
|
34
|
+
}
|
|
18
35
|
get route() {
|
|
19
36
|
const route = this.transition.route;
|
|
20
37
|
if (route === null) {
|
|
@@ -28,24 +45,12 @@ export class Router {
|
|
|
28
45
|
return this.parsedOptions.root;
|
|
29
46
|
}
|
|
30
47
|
get req() {
|
|
31
|
-
|
|
48
|
+
var _a;
|
|
49
|
+
return (_a = this.parsedOptions.req) != null ? _a : null;
|
|
32
50
|
}
|
|
33
51
|
get res() {
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
constructor(options) {
|
|
37
|
-
this.options = options;
|
|
38
|
-
this.parsedOptions = parsedOptions(options);
|
|
39
|
-
this.isLayer = this.parsedOptions.layer;
|
|
40
|
-
this.navigation = new Navigation(
|
|
41
|
-
this.parsedOptions,
|
|
42
|
-
(url, state) => {
|
|
43
|
-
this.transition.to(RouteType.unknown, {
|
|
44
|
-
url,
|
|
45
|
-
state
|
|
46
|
-
});
|
|
47
|
-
}
|
|
48
|
-
);
|
|
52
|
+
var _a;
|
|
53
|
+
return (_a = this.parsedOptions.res) != null ? _a : null;
|
|
49
54
|
}
|
|
50
55
|
push(toInput) {
|
|
51
56
|
return this.transition.to(RouteType.push, toInput);
|
|
@@ -62,7 +67,7 @@ export class Router {
|
|
|
62
67
|
restartApp(toInput) {
|
|
63
68
|
return this.transition.to(
|
|
64
69
|
RouteType.restartApp,
|
|
65
|
-
toInput
|
|
70
|
+
toInput != null ? toInput : this.route.url.href
|
|
66
71
|
);
|
|
67
72
|
}
|
|
68
73
|
async back() {
|
|
@@ -132,12 +137,12 @@ export class Router {
|
|
|
132
137
|
* ```
|
|
133
138
|
*/
|
|
134
139
|
resolve(toInput, toType) {
|
|
135
|
-
var _a;
|
|
140
|
+
var _a, _b;
|
|
136
141
|
return new Route({
|
|
137
142
|
options: this.parsedOptions,
|
|
138
143
|
toType,
|
|
139
144
|
toInput,
|
|
140
|
-
from: ((_a = this.transition.route) == null ? void 0 : _a.url)
|
|
145
|
+
from: (_b = (_a = this.transition.route) == null ? void 0 : _a.url) != null ? _b : null
|
|
141
146
|
});
|
|
142
147
|
}
|
|
143
148
|
/**
|
|
@@ -194,10 +199,11 @@ export class Router {
|
|
|
194
199
|
return createLinkResolver(this, props);
|
|
195
200
|
}
|
|
196
201
|
async createLayer(toInput) {
|
|
197
|
-
|
|
198
|
-
const
|
|
202
|
+
var _a;
|
|
203
|
+
const layerOptions = isPlainObject(toInput) && toInput.layer || {};
|
|
204
|
+
const zIndex = (_a = layerOptions.zIndex) != null ? _a : this.parsedOptions.zIndex + LAYER_ID.next();
|
|
199
205
|
let promiseResolve;
|
|
200
|
-
|
|
206
|
+
let promise = new Promise((resolve) => {
|
|
201
207
|
promiseResolve = resolve;
|
|
202
208
|
});
|
|
203
209
|
const router = new Router({
|
|
@@ -245,7 +251,7 @@ export class Router {
|
|
|
245
251
|
router.afterEach((to, from) => {
|
|
246
252
|
if (layerOptions.shouldClose) {
|
|
247
253
|
const result = layerOptions.shouldClose(to, from, router);
|
|
248
|
-
if (result ===
|
|
254
|
+
if (result === true) {
|
|
249
255
|
router.destroy();
|
|
250
256
|
promiseResolve({
|
|
251
257
|
type: "push",
|
|
@@ -259,6 +265,18 @@ export class Router {
|
|
|
259
265
|
router.route.state,
|
|
260
266
|
router.route.url
|
|
261
267
|
);
|
|
268
|
+
promise = promise.then(async (result) => {
|
|
269
|
+
await this.navigation.backHistoryState();
|
|
270
|
+
return result;
|
|
271
|
+
});
|
|
272
|
+
}
|
|
273
|
+
if (layerOptions.autoPush) {
|
|
274
|
+
promise = promise.then(async (result) => {
|
|
275
|
+
if (result.type === "push") {
|
|
276
|
+
await this.push(result.route.url.href);
|
|
277
|
+
}
|
|
278
|
+
return result;
|
|
279
|
+
});
|
|
262
280
|
}
|
|
263
281
|
return {
|
|
264
282
|
promise,
|
|
@@ -277,7 +295,7 @@ export class Router {
|
|
|
277
295
|
var _a, _b;
|
|
278
296
|
try {
|
|
279
297
|
const result = await ((_b = (_a = this.microApp.app) == null ? void 0 : _a.renderToString) == null ? void 0 : _b.call(_a));
|
|
280
|
-
return result
|
|
298
|
+
return result != null ? result : null;
|
|
281
299
|
} catch (e) {
|
|
282
300
|
if (throwError) throw e;
|
|
283
301
|
else console.error(e);
|
package/dist/types.d.ts
CHANGED
|
@@ -214,6 +214,7 @@ export interface RouterLinkAttributes {
|
|
|
214
214
|
target?: '_blank';
|
|
215
215
|
rel?: string;
|
|
216
216
|
}
|
|
217
|
+
export type RouterLinkEventHandler = <E extends Event = MouseEvent>(event: E) => boolean | void;
|
|
217
218
|
/**
|
|
218
219
|
* Framework-agnostic link configuration interface
|
|
219
220
|
*/
|
|
@@ -229,6 +230,7 @@ export interface RouterLinkProps {
|
|
|
229
230
|
event?: string | string[];
|
|
230
231
|
tag?: string;
|
|
231
232
|
layerOptions?: RouteLayerOptions;
|
|
233
|
+
eventHandler?: RouterLinkEventHandler;
|
|
232
234
|
}
|
|
233
235
|
/**
|
|
234
236
|
* Framework-agnostic link resolution result
|
|
@@ -241,6 +243,6 @@ export interface RouterLinkResolved {
|
|
|
241
243
|
isExternal: boolean;
|
|
242
244
|
tag: string;
|
|
243
245
|
attributes: RouterLinkAttributes;
|
|
244
|
-
navigate: (e?:
|
|
245
|
-
getEventHandlers: (nameTransform?: (eventType: string) => string) => Record<string, (e:
|
|
246
|
+
navigate: (e?: Event) => Promise<void>;
|
|
247
|
+
getEventHandlers: (nameTransform?: (eventType: string) => string) => Record<string, (e: Event) => Promise<void> | undefined>;
|
|
246
248
|
}
|
package/dist/util.test.mjs
CHANGED
|
@@ -23,8 +23,8 @@ describe("isNotNullish", () => {
|
|
|
23
23
|
expect(isNotNullish(new Number("a"))).toBe(false);
|
|
24
24
|
expect(isNotNullish(0)).toBe(true);
|
|
25
25
|
expect(isNotNullish(123)).toBe(true);
|
|
26
|
-
expect(isNotNullish(
|
|
27
|
-
expect(isNotNullish(
|
|
26
|
+
expect(isNotNullish(/* @__PURE__ */ BigInt("123"))).toBe(true);
|
|
27
|
+
expect(isNotNullish(/* @__PURE__ */ BigInt("0"))).toBe(true);
|
|
28
28
|
expect(isNotNullish(new Number("1"))).toBe(true);
|
|
29
29
|
expect(isNotNullish(Number.POSITIVE_INFINITY)).toBe(true);
|
|
30
30
|
expect(isNotNullish(Number.NEGATIVE_INFINITY)).toBe(true);
|
|
@@ -171,9 +171,9 @@ describe("isPlainObject", () => {
|
|
|
171
171
|
expect(isPlainObject(new Boolean(true))).toBe(false);
|
|
172
172
|
expect(isPlainObject(new Boolean(false))).toBe(false);
|
|
173
173
|
expect(isPlainObject(0)).toBe(false);
|
|
174
|
-
expect(isPlainObject(
|
|
174
|
+
expect(isPlainObject(/* @__PURE__ */ BigInt("0"))).toBe(false);
|
|
175
175
|
expect(isPlainObject(123)).toBe(false);
|
|
176
|
-
expect(isPlainObject(
|
|
176
|
+
expect(isPlainObject(/* @__PURE__ */ BigInt("123"))).toBe(false);
|
|
177
177
|
expect(isPlainObject(new Number("1"))).toBe(false);
|
|
178
178
|
expect(isPlainObject(+"a")).toBe(false);
|
|
179
179
|
expect(isPlainObject(Number.NaN)).toBe(false);
|
|
@@ -249,8 +249,8 @@ describe("isNonEmptyPlainObject", () => {
|
|
|
249
249
|
expect(isNonEmptyPlainObject("non-empty")).toBe(false);
|
|
250
250
|
expect(isNonEmptyPlainObject(0)).toBe(false);
|
|
251
251
|
expect(isNonEmptyPlainObject(123)).toBe(false);
|
|
252
|
-
expect(isNonEmptyPlainObject(
|
|
253
|
-
expect(isNonEmptyPlainObject(
|
|
252
|
+
expect(isNonEmptyPlainObject(/* @__PURE__ */ BigInt("0"))).toBe(false);
|
|
253
|
+
expect(isNonEmptyPlainObject(/* @__PURE__ */ BigInt("123"))).toBe(false);
|
|
254
254
|
expect(isNonEmptyPlainObject(true)).toBe(false);
|
|
255
255
|
expect(isNonEmptyPlainObject(false)).toBe(false);
|
|
256
256
|
expect(isNonEmptyPlainObject(Symbol("test"))).toBe(false);
|
|
@@ -381,12 +381,12 @@ describe("removeFromArray", () => {
|
|
|
381
381
|
expect(complexArr).toHaveLength(2);
|
|
382
382
|
});
|
|
383
383
|
test("should handle arrays with different primitive types", () => {
|
|
384
|
-
let mixedArr = [1, "1", true,
|
|
384
|
+
let mixedArr = [1, "1", true, /* @__PURE__ */ BigInt("1"), Symbol("test")];
|
|
385
385
|
removeFromArray(mixedArr, 1);
|
|
386
|
-
expect(mixedArr).toEqual(["1", true,
|
|
387
|
-
mixedArr = [1, "1", true,
|
|
386
|
+
expect(mixedArr).toEqual(["1", true, /* @__PURE__ */ BigInt("1"), expect.any(Symbol)]);
|
|
387
|
+
mixedArr = [1, "1", true, /* @__PURE__ */ BigInt("1"), Symbol("test")];
|
|
388
388
|
removeFromArray(mixedArr, "1");
|
|
389
|
-
expect(mixedArr).toEqual([1, true,
|
|
389
|
+
expect(mixedArr).toEqual([1, true, /* @__PURE__ */ BigInt("1"), expect.any(Symbol)]);
|
|
390
390
|
const mixedArray = [
|
|
391
391
|
"string",
|
|
392
392
|
42,
|
|
@@ -496,8 +496,8 @@ describe("isValidConfirmHookResult", () => {
|
|
|
496
496
|
expect(isValidConfirmHookResult(void 0)).toBe(false);
|
|
497
497
|
expect(isValidConfirmHookResult(123)).toBe(false);
|
|
498
498
|
expect(isValidConfirmHookResult(0)).toBe(false);
|
|
499
|
-
expect(isValidConfirmHookResult(
|
|
500
|
-
expect(isValidConfirmHookResult(
|
|
499
|
+
expect(isValidConfirmHookResult(/* @__PURE__ */ BigInt("123"))).toBe(false);
|
|
500
|
+
expect(isValidConfirmHookResult(/* @__PURE__ */ BigInt("0"))).toBe(false);
|
|
501
501
|
expect(isValidConfirmHookResult(new Number("1"))).toBe(false);
|
|
502
502
|
expect(isValidConfirmHookResult(+"a")).toBe(false);
|
|
503
503
|
expect(isValidConfirmHookResult(Number.NaN)).toBe(false);
|
|
@@ -798,11 +798,11 @@ describe("isUrlEqual", () => {
|
|
|
798
798
|
const params1 = new URLSearchParams();
|
|
799
799
|
const params2 = new URLSearchParams();
|
|
800
800
|
for (let i = 0; i < 100; i++) {
|
|
801
|
-
params1.append(
|
|
802
|
-
params2.append(
|
|
801
|
+
params1.append("param".concat(i), "value".concat(i));
|
|
802
|
+
params2.append("param".concat(99 - i), "value".concat(99 - i));
|
|
803
803
|
}
|
|
804
|
-
const url1 = new URL(
|
|
805
|
-
const url2 = new URL(
|
|
804
|
+
const url1 = new URL("https://example.com/path?".concat(params1));
|
|
805
|
+
const url2 = new URL("https://example.com/path?".concat(params2));
|
|
806
806
|
const start = performance.now();
|
|
807
807
|
const result = isUrlEqual(url1, url2);
|
|
808
808
|
const end = performance.now();
|
|
@@ -812,10 +812,10 @@ describe("isUrlEqual", () => {
|
|
|
812
812
|
test("should handle complex real-world scenarios", () => {
|
|
813
813
|
const baseUrl = "https://api.example.com/v1/users";
|
|
814
814
|
const url1 = new URL(
|
|
815
|
-
|
|
815
|
+
"".concat(baseUrl, "?page=1&limit=20&sort=name&filter=active&tag=user&tag=admin")
|
|
816
816
|
);
|
|
817
817
|
const url2 = new URL(
|
|
818
|
-
|
|
818
|
+
"".concat(baseUrl, "?limit=20&tag=user&page=1&tag=admin&filter=active&sort=name")
|
|
819
819
|
);
|
|
820
820
|
expect(isUrlEqual(url1, url2)).toBe(true);
|
|
821
821
|
const oauthUrl1 = new URL(
|
package/package.json
CHANGED
|
@@ -32,16 +32,16 @@
|
|
|
32
32
|
},
|
|
33
33
|
"devDependencies": {
|
|
34
34
|
"@biomejs/biome": "1.9.4",
|
|
35
|
-
"@esmx/lint": "3.0.0-rc.
|
|
36
|
-
"@types/node": "
|
|
37
|
-
"@vitest/coverage-v8": "3.
|
|
35
|
+
"@esmx/lint": "3.0.0-rc.26",
|
|
36
|
+
"@types/node": "^24.0.10",
|
|
37
|
+
"@vitest/coverage-v8": "3.2.4",
|
|
38
38
|
"happy-dom": "^18.0.1",
|
|
39
|
-
"stylelint": "16.
|
|
40
|
-
"typescript": "5.8.
|
|
39
|
+
"stylelint": "16.21.0",
|
|
40
|
+
"typescript": "5.8.3",
|
|
41
41
|
"unbuild": "3.5.0",
|
|
42
|
-
"vitest": "3.
|
|
42
|
+
"vitest": "3.2.4"
|
|
43
43
|
},
|
|
44
|
-
"version": "3.0.0-rc.
|
|
44
|
+
"version": "3.0.0-rc.26",
|
|
45
45
|
"type": "module",
|
|
46
46
|
"private": false,
|
|
47
47
|
"exports": {
|
|
@@ -60,5 +60,5 @@
|
|
|
60
60
|
"template",
|
|
61
61
|
"public"
|
|
62
62
|
],
|
|
63
|
-
"gitHead": "
|
|
63
|
+
"gitHead": "2f52f94c8ac27aca32ef3148afd109d0f0470d52"
|
|
64
64
|
}
|
package/src/navigation.ts
CHANGED
|
@@ -86,7 +86,11 @@ export class Navigation {
|
|
|
86
86
|
this._replace(history, data, url);
|
|
87
87
|
}
|
|
88
88
|
|
|
89
|
-
public
|
|
89
|
+
public backHistoryState() {
|
|
90
|
+
return this._go(history, -1);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
private _go(history: History, index: number): Promise<NavigationGoResult> {
|
|
90
94
|
if (this._promiseResolve) {
|
|
91
95
|
return Promise.resolve(null);
|
|
92
96
|
}
|
|
@@ -97,9 +101,12 @@ export class Navigation {
|
|
|
97
101
|
resolve({ type: 'success', url, state: state || {} });
|
|
98
102
|
};
|
|
99
103
|
setTimeout(this._promiseResolve, 80);
|
|
100
|
-
|
|
104
|
+
history.go(index);
|
|
101
105
|
});
|
|
102
106
|
}
|
|
107
|
+
public go(delta?: number): Promise<NavigationGoResult> {
|
|
108
|
+
return this._go(this._history, delta || 0);
|
|
109
|
+
}
|
|
103
110
|
public forward(): Promise<NavigationGoResult> {
|
|
104
111
|
return this.go(1);
|
|
105
112
|
}
|
package/src/route-transition.ts
CHANGED
|
@@ -380,7 +380,7 @@ export class RouteTransition {
|
|
|
380
380
|
toType: RouteType,
|
|
381
381
|
toInput: RouteLocationInput
|
|
382
382
|
): Promise<Route> {
|
|
383
|
-
const from = this.route;
|
|
383
|
+
const from = this.route?.clone() ?? null;
|
|
384
384
|
const to = await this._runTask(
|
|
385
385
|
new Route({
|
|
386
386
|
options: this.router.parsedOptions,
|