@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.
@@ -18,9 +18,13 @@ function getEventTypeList(eventType) {
18
18
  return validEvents.length ? validEvents : ["click"];
19
19
  }
20
20
  function guardEvent(e) {
21
- if (e.metaKey || e.altKey || e.ctrlKey || e.shiftKey) return false;
22
- if (e.defaultPrevented) return false;
23
- if (e.button !== void 0 && e.button !== 0) return false;
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
- if (e && !guardEvent(e)) {
54
- return;
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
- const eventName = nameTransform ? nameTransform(eventType) : eventType.toLowerCase();
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
- `beforeEach-${to.path}-from-${(from == null ? void 0 : from.path) || "null"}`
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
- `afterEach-${to.path}-from-${(from == null ? void 0 : from.path) || "null"}`
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(`global-beforeEach-${to.path}`);
507
+ lifecycleLog.push("global-beforeEach-".concat(to.path));
508
508
  });
509
509
  const unregisterAfter = lifecycleRouter.afterEach((to, from) => {
510
- lifecycleLog.push(`global-afterEach-${to.path}`);
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(`/user/${i}`);
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(`/user/${i}`).catch((err) => err)
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(`\u{1FA9F} ${methodName} Core Functionality Tests`, () => {
37
- it(`should support using current route path`, async () => {
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(`should support string path parameters`, async () => {
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(`should support object parameters`, async () => {
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(`should correctly handle complete URLs`, async () => {
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(`\u{1F3AF} ${methodName} Specific Behavior Tests`, () => {
80
- it(`should set correct isPush flag`, async () => {
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(`should call location handler`, async () => {
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(`should not update current route state`, async () => {
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(`should not trigger MicroApp update`, async () => {
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(`\u{1F6E1}\uFE0F ${methodName} Route Guards Tests`, () => {
119
- it(`should execute beforeEach guards`, async () => {
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(`should abort navigation when guard returns false`, async () => {
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(`should support guard redirects`, async () => {
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(`should execute afterEach guards`, async () => {
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(`\u{1F3AD} ${methodName} Edge Cases Tests`, () => {
161
- it(`should handle non-existent routes`, async () => {
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(`should handle empty string path`, async () => {
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(`should handle special characters`, async () => {
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(`\u26A1 ${methodName} Task Cancellation and Concurrency Control`, () => {
184
- it(`should support concurrent calls`, async () => {
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(`should correctly handle rapid consecutive calls`, async () => {
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](`/user/${i}`));
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(`\u274C ${methodName} Error Handling`, () => {
214
- it(`should handle exceptions in guards`, async () => {
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(`should handle location handler exceptions`, async () => {
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(`\u{1F9E9} ${methodName} Async Component Handling`, () => {
237
- it(`should correctly handle async components`, async () => {
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(`should handle async component loading failures`, async () => {
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(`\u{1F527} ${methodName} Differences from Other Methods`, () => {
289
- it(`should behave differently from push/replace methods`, async () => {
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(`should maintain consistency with resolve method in URL parsing`, async () => {
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
- parsedOptions;
13
- isLayer;
14
- navigation;
15
- microApp = new MicroApp();
16
- // Route transition manager
17
- transition = new RouteTransition(this);
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
- return this.parsedOptions.req ?? null;
48
+ var _a;
49
+ return (_a = this.parsedOptions.req) != null ? _a : null;
32
50
  }
33
51
  get res() {
34
- return this.parsedOptions.res ?? null;
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 ?? this.route.url.href
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) ?? null
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
- const layerOptions = (isPlainObject(toInput) ? toInput.layer : null) || {};
198
- const zIndex = layerOptions.zIndex ?? this.parsedOptions.zIndex + LAYER_ID.next();
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
- const promise = new Promise((resolve) => {
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 === false) {
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 ?? null;
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?: MouseEvent) => Promise<void>;
245
- getEventHandlers: (nameTransform?: (eventType: string) => string) => Record<string, (e: MouseEvent) => Promise<void>>;
246
+ navigate: (e?: Event) => Promise<void>;
247
+ getEventHandlers: (nameTransform?: (eventType: string) => string) => Record<string, (e: Event) => Promise<void> | undefined>;
246
248
  }
@@ -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(123n)).toBe(true);
27
- expect(isNotNullish(0n)).toBe(true);
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(0n)).toBe(false);
174
+ expect(isPlainObject(/* @__PURE__ */ BigInt("0"))).toBe(false);
175
175
  expect(isPlainObject(123)).toBe(false);
176
- expect(isPlainObject(123n)).toBe(false);
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(0n)).toBe(false);
253
- expect(isNonEmptyPlainObject(123n)).toBe(false);
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, 1n, Symbol("test")];
384
+ let mixedArr = [1, "1", true, /* @__PURE__ */ BigInt("1"), Symbol("test")];
385
385
  removeFromArray(mixedArr, 1);
386
- expect(mixedArr).toEqual(["1", true, 1n, expect.any(Symbol)]);
387
- mixedArr = [1, "1", true, 1n, Symbol("test")];
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, 1n, expect.any(Symbol)]);
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(123n)).toBe(false);
500
- expect(isValidConfirmHookResult(0n)).toBe(false);
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(`param${i}`, `value${i}`);
802
- params2.append(`param${99 - i}`, `value${99 - i}`);
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(`https://example.com/path?${params1}`);
805
- const url2 = new URL(`https://example.com/path?${params2}`);
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
- `${baseUrl}?page=1&limit=20&sort=name&filter=active&tag=user&tag=admin`
815
+ "".concat(baseUrl, "?page=1&limit=20&sort=name&filter=active&tag=user&tag=admin")
816
816
  );
817
817
  const url2 = new URL(
818
- `${baseUrl}?limit=20&tag=user&page=1&tag=admin&filter=active&sort=name`
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.24",
36
- "@types/node": "22.15.18",
37
- "@vitest/coverage-v8": "3.1.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.19.1",
40
- "typescript": "5.8.2",
39
+ "stylelint": "16.21.0",
40
+ "typescript": "5.8.3",
41
41
  "unbuild": "3.5.0",
42
- "vitest": "3.1.3"
42
+ "vitest": "3.2.4"
43
43
  },
44
- "version": "3.0.0-rc.24",
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": "ef6208ea42a7105ca056ca9cd3c364d989c4d97d"
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 go(index: number): Promise<NavigationGoResult> {
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
- this._history.go(index);
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
  }
@@ -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,