@esmx/router 3.0.0-rc.25 → 3.0.0-rc.27

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,7 +18,9 @@ export declare class Navigation {
18
18
  replace(data: any, url?: string | URL | null): RouteState;
19
19
  pushHistoryState(data: any, url?: string | URL | null): void;
20
20
  replaceHistoryState(data: any, url?: string | URL | null): void;
21
- go(index: number): Promise<NavigationGoResult>;
21
+ backHistoryState(): Promise<NavigationGoResult>;
22
+ private _go;
23
+ go(delta?: number): Promise<NavigationGoResult>;
22
24
  forward(): Promise<NavigationGoResult>;
23
25
  back(): Promise<NavigationGoResult>;
24
26
  destroy(): void;
@@ -53,7 +53,10 @@ export class Navigation {
53
53
  replaceHistoryState(data, url) {
54
54
  this._replace(history, data, url);
55
55
  }
56
- go(index) {
56
+ backHistoryState() {
57
+ return this._go(history, -1);
58
+ }
59
+ _go(history2, index) {
57
60
  if (this._promiseResolve) {
58
61
  return Promise.resolve(null);
59
62
  }
@@ -64,9 +67,12 @@ export class Navigation {
64
67
  resolve({ type: "success", url, state: state || {} });
65
68
  };
66
69
  setTimeout(this._promiseResolve, 80);
67
- this._history.go(index);
70
+ history2.go(index);
68
71
  });
69
72
  }
73
+ go(delta) {
74
+ return this._go(this._history, delta || 0);
75
+ }
70
76
  forward() {
71
77
  return this.go(1);
72
78
  }
@@ -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;
package/dist/router.mjs CHANGED
@@ -200,10 +200,10 @@ export class Router {
200
200
  }
201
201
  async createLayer(toInput) {
202
202
  var _a;
203
- const layerOptions = (isPlainObject(toInput) ? toInput.layer : null) || {};
203
+ const layerOptions = isPlainObject(toInput) && toInput.layer || {};
204
204
  const zIndex = (_a = layerOptions.zIndex) != null ? _a : this.parsedOptions.zIndex + LAYER_ID.next();
205
205
  let promiseResolve;
206
- const promise = new Promise((resolve) => {
206
+ let promise = new Promise((resolve) => {
207
207
  promiseResolve = resolve;
208
208
  });
209
209
  const router = new Router({
@@ -265,6 +265,18 @@ export class Router {
265
265
  router.route.state,
266
266
  router.route.url
267
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
+ });
268
280
  }
269
281
  return {
270
282
  promise,
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
  }
package/package.json CHANGED
@@ -32,7 +32,7 @@
32
32
  },
33
33
  "devDependencies": {
34
34
  "@biomejs/biome": "1.9.4",
35
- "@esmx/lint": "3.0.0-rc.25",
35
+ "@esmx/lint": "3.0.0-rc.27",
36
36
  "@types/node": "^24.0.10",
37
37
  "@vitest/coverage-v8": "3.2.4",
38
38
  "happy-dom": "^18.0.1",
@@ -41,7 +41,7 @@
41
41
  "unbuild": "3.5.0",
42
42
  "vitest": "3.2.4"
43
43
  },
44
- "version": "3.0.0-rc.25",
44
+ "version": "3.0.0-rc.27",
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": "da6576d7505ad48cb78905b18e17940d43510250"
63
+ "gitHead": "79ce8ceea4a9c738d9ebeb4607d925fc411d3df1"
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
  }
@@ -43,19 +43,24 @@ function getEventTypeList(eventType: unknown | unknown[]): string[] {
43
43
  /**
44
44
  * Event guard check - determines if the router should handle the navigation
45
45
  *
46
- * Returns false: Let browser handle default behavior (normal link navigation)
47
- * Returns true: Router takes over navigation, prevents default browser behavior
46
+ * Returns !0: Let browser handle default behavior (normal link navigation)
47
+ * Returns 0: Router takes over navigation, prevents default browser behavior
48
48
  *
49
49
  * This function intelligently decides when to let the browser handle clicks
50
50
  * (like Ctrl+click for new tabs) vs when to use SPA routing
51
51
  */
52
- function guardEvent(e: MouseEvent): boolean {
52
+ function guardEvent(e?: Event & Partial<MouseEvent>): true | undefined {
53
+ if (!e) return;
53
54
  // don't redirect with control keys
54
- if (e.metaKey || e.altKey || e.ctrlKey || e.shiftKey) return false;
55
+ if (e.metaKey || e.altKey || e.ctrlKey || e.shiftKey) return;
55
56
  // don't redirect when preventDefault called
56
- if (e.defaultPrevented) return false;
57
+ if (e.defaultPrevented) return;
57
58
  // don't redirect on right click
58
- if (e.button !== undefined && e.button !== 0) return false;
59
+ if (e.button !== undefined && e.button !== 0) return;
60
+ // don't redirect if `target="_blank"`
61
+ // @ts-expect-error getAttribute exists
62
+ const target = e.currentTarget?.getAttribute?.('target') ?? '';
63
+ if (/\b_blank\b/i.test(target)) return;
59
64
  // Prevent default browser navigation to enable SPA routing
60
65
  // Note: this may be a Weex event which doesn't have this method
61
66
  if (e.preventDefault) e.preventDefault();
@@ -107,11 +112,10 @@ function createNavigateFunction(
107
112
  router: Router,
108
113
  props: RouterLinkProps,
109
114
  navigationType: RouterLinkType
110
- ): (e?: MouseEvent) => Promise<void> {
111
- return async (e?: MouseEvent): Promise<void> => {
112
- if (e && !guardEvent(e)) {
113
- return;
114
- }
115
+ ): (e?: Event) => Promise<void> {
116
+ return async (e?: Event): Promise<void> => {
117
+ const eventHandler = props.eventHandler ?? guardEvent;
118
+ if (!eventHandler(e!)) return;
115
119
 
116
120
  await executeNavigation(router, props, navigationType);
117
121
  };
@@ -169,18 +173,17 @@ function computeAttributes(
169
173
  * Create event handlers generator function
170
174
  */
171
175
  function createEventHandlersGenerator(
172
- navigate: (e?: MouseEvent) => Promise<void>,
176
+ navigate: (e: Event) => Promise<void>,
173
177
  eventTypes: string[]
174
178
  ): (
175
179
  nameTransform?: (eventType: string) => string
176
- ) => Record<string, (e: MouseEvent) => Promise<void>> {
180
+ ) => Record<string, (e: Event) => Promise<void>> {
177
181
  return (nameTransform?: (eventType: string) => string) => {
178
- const handlers: Record<string, (e: MouseEvent) => Promise<void>> = {};
182
+ const handlers: Record<string, (e: Event) => Promise<void>> = {};
179
183
 
180
184
  eventTypes.forEach((eventType) => {
181
- const eventName = nameTransform
182
- ? nameTransform(eventType)
183
- : eventType.toLowerCase();
185
+ const eventName =
186
+ nameTransform?.(eventType) ?? eventType.toLowerCase();
184
187
  handlers[eventName] = navigate;
185
188
  });
186
189
 
package/src/router.ts CHANGED
@@ -227,13 +227,13 @@ export class Router {
227
227
  toInput: RouteLocationInput
228
228
  ): Promise<{ promise: Promise<RouteLayerResult>; router: Router }> {
229
229
  const layerOptions: RouteLayerOptions =
230
- (isPlainObject(toInput) ? toInput.layer : null) || {};
230
+ (isPlainObject(toInput) && toInput.layer) || {};
231
231
 
232
232
  const zIndex =
233
233
  layerOptions.zIndex ?? this.parsedOptions.zIndex + LAYER_ID.next();
234
234
 
235
235
  let promiseResolve: (result: RouteLayerResult) => void;
236
- const promise = new Promise<RouteLayerResult>((resolve) => {
236
+ let promise = new Promise<RouteLayerResult>((resolve) => {
237
237
  promiseResolve = resolve;
238
238
  });
239
239
 
@@ -297,6 +297,18 @@ export class Router {
297
297
  router.route.state,
298
298
  router.route.url
299
299
  );
300
+ promise = promise.then(async (result) => {
301
+ await this.navigation.backHistoryState();
302
+ return result;
303
+ });
304
+ }
305
+ if (layerOptions.autoPush) {
306
+ promise = promise.then(async (result) => {
307
+ if (result.type === 'push') {
308
+ await this.push(result.route.url.href);
309
+ }
310
+ return result;
311
+ });
300
312
  }
301
313
  return {
302
314
  promise,
package/src/types.ts CHANGED
@@ -299,6 +299,10 @@ export interface RouterLinkAttributes {
299
299
  rel?: string;
300
300
  }
301
301
 
302
+ export type RouterLinkEventHandler = <E extends Event = MouseEvent>(
303
+ event: E
304
+ ) => boolean | void;
305
+
302
306
  /**
303
307
  * Framework-agnostic link configuration interface
304
308
  */
@@ -314,6 +318,7 @@ export interface RouterLinkProps {
314
318
  event?: string | string[];
315
319
  tag?: string;
316
320
  layerOptions?: RouteLayerOptions;
321
+ eventHandler?: RouterLinkEventHandler;
317
322
  }
318
323
 
319
324
  /**
@@ -332,10 +337,10 @@ export interface RouterLinkResolved {
332
337
  attributes: RouterLinkAttributes;
333
338
 
334
339
  // Navigation function
335
- navigate: (e?: MouseEvent) => Promise<void>;
340
+ navigate: (e?: Event) => Promise<void>;
336
341
 
337
342
  // Event handling
338
343
  getEventHandlers: (
339
344
  nameTransform?: (eventType: string) => string
340
- ) => Record<string, (e: MouseEvent) => Promise<void>>;
345
+ ) => Record<string, (e: Event) => Promise<void> | undefined>;
341
346
  }