@esmx/router 3.0.0-rc.12 → 3.0.0-rc.120

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.
Files changed (105) hide show
  1. package/README.md +158 -0
  2. package/README.zh-CN.md +158 -0
  3. package/dist/error.d.ts +23 -0
  4. package/dist/error.mjs +64 -0
  5. package/dist/increment-id.d.ts +7 -0
  6. package/dist/increment-id.mjs +16 -0
  7. package/dist/index.d.ts +14 -3
  8. package/dist/index.mjs +13 -3
  9. package/dist/location.d.ts +22 -0
  10. package/dist/location.mjs +64 -0
  11. package/dist/matcher.d.ts +4 -0
  12. package/dist/matcher.mjs +49 -0
  13. package/dist/micro-app.d.ts +20 -0
  14. package/dist/micro-app.mjs +132 -0
  15. package/dist/navigation.d.ts +45 -0
  16. package/dist/navigation.mjs +153 -0
  17. package/dist/options.d.ts +4 -0
  18. package/dist/options.mjs +95 -0
  19. package/dist/route-task.d.ts +40 -0
  20. package/dist/route-task.mjs +77 -0
  21. package/dist/route-transition.d.ts +54 -0
  22. package/dist/route-transition.mjs +362 -0
  23. package/dist/route.d.ts +77 -0
  24. package/dist/route.mjs +223 -0
  25. package/dist/router-link.d.ts +10 -0
  26. package/dist/router-link.mjs +142 -0
  27. package/dist/router.d.ts +113 -102
  28. package/dist/router.mjs +321 -354
  29. package/dist/scroll.d.ts +33 -0
  30. package/dist/scroll.mjs +50 -0
  31. package/dist/types.d.ts +312 -0
  32. package/dist/types.mjs +18 -0
  33. package/dist/util.d.ts +32 -0
  34. package/dist/util.mjs +100 -0
  35. package/package.json +42 -15
  36. package/src/error.ts +84 -0
  37. package/src/increment-id.ts +12 -0
  38. package/src/index.ts +67 -3
  39. package/src/location.ts +124 -0
  40. package/src/matcher.ts +71 -0
  41. package/src/micro-app.ts +153 -0
  42. package/src/navigation.ts +202 -0
  43. package/src/options.ts +136 -0
  44. package/src/route-task.ts +102 -0
  45. package/src/route-transition.ts +480 -0
  46. package/src/route.ts +335 -0
  47. package/src/router-link.ts +241 -0
  48. package/src/router.ts +351 -467
  49. package/src/scroll.ts +106 -0
  50. package/src/types.ts +415 -0
  51. package/src/util.ts +184 -0
  52. package/dist/history/abstract.d.ts +0 -29
  53. package/dist/history/abstract.mjs +0 -107
  54. package/dist/history/base.d.ts +0 -79
  55. package/dist/history/base.mjs +0 -275
  56. package/dist/history/html.d.ts +0 -22
  57. package/dist/history/html.mjs +0 -181
  58. package/dist/history/index.d.ts +0 -7
  59. package/dist/history/index.mjs +0 -16
  60. package/dist/matcher/create-matcher.d.ts +0 -5
  61. package/dist/matcher/create-matcher.mjs +0 -218
  62. package/dist/matcher/create-matcher.spec.d.ts +0 -1
  63. package/dist/matcher/create-matcher.spec.mjs +0 -0
  64. package/dist/matcher/index.d.ts +0 -1
  65. package/dist/matcher/index.mjs +0 -1
  66. package/dist/task-pipe/index.d.ts +0 -1
  67. package/dist/task-pipe/index.mjs +0 -1
  68. package/dist/task-pipe/task.d.ts +0 -30
  69. package/dist/task-pipe/task.mjs +0 -66
  70. package/dist/utils/bom.d.ts +0 -5
  71. package/dist/utils/bom.mjs +0 -10
  72. package/dist/utils/encoding.d.ts +0 -48
  73. package/dist/utils/encoding.mjs +0 -44
  74. package/dist/utils/guards.d.ts +0 -9
  75. package/dist/utils/guards.mjs +0 -12
  76. package/dist/utils/index.d.ts +0 -7
  77. package/dist/utils/index.mjs +0 -27
  78. package/dist/utils/path.d.ts +0 -60
  79. package/dist/utils/path.mjs +0 -264
  80. package/dist/utils/path.spec.d.ts +0 -1
  81. package/dist/utils/path.spec.mjs +0 -30
  82. package/dist/utils/scroll.d.ts +0 -25
  83. package/dist/utils/scroll.mjs +0 -59
  84. package/dist/utils/utils.d.ts +0 -16
  85. package/dist/utils/utils.mjs +0 -11
  86. package/dist/utils/warn.d.ts +0 -2
  87. package/dist/utils/warn.mjs +0 -12
  88. package/src/history/abstract.ts +0 -149
  89. package/src/history/base.ts +0 -408
  90. package/src/history/html.ts +0 -231
  91. package/src/history/index.ts +0 -20
  92. package/src/matcher/create-matcher.spec.ts +0 -3
  93. package/src/matcher/create-matcher.ts +0 -293
  94. package/src/matcher/index.ts +0 -1
  95. package/src/task-pipe/index.ts +0 -1
  96. package/src/task-pipe/task.ts +0 -97
  97. package/src/utils/bom.ts +0 -14
  98. package/src/utils/encoding.ts +0 -153
  99. package/src/utils/guards.ts +0 -25
  100. package/src/utils/index.ts +0 -27
  101. package/src/utils/path.spec.ts +0 -44
  102. package/src/utils/path.ts +0 -397
  103. package/src/utils/scroll.ts +0 -120
  104. package/src/utils/utils.ts +0 -30
  105. package/src/utils/warn.ts +0 -13
package/README.md ADDED
@@ -0,0 +1,158 @@
1
+ <div align="center">
2
+ <img src="https://esmx.dev/logo.svg?t=2025" width="120" alt="Esmx Logo" />
3
+ <h1>@esmx/router</h1>
4
+
5
+ <div>
6
+ <a href="https://www.npmjs.com/package/@esmx/router">
7
+ <img src="https://img.shields.io/npm/v/@esmx/router.svg" alt="npm version" />
8
+ </a>
9
+ <a href="https://github.com/esmnext/esmx/actions/workflows/build.yml">
10
+ <img src="https://github.com/esmnext/esmx/actions/workflows/build.yml/badge.svg" alt="Build" />
11
+ </a>
12
+ <a href="https://esmx.dev/coverage/">
13
+ <img src="https://img.shields.io/badge/coverage-live%20report-brightgreen" alt="Coverage Report" />
14
+ </a>
15
+ <a href="https://nodejs.org/">
16
+ <img src="https://img.shields.io/node/v/@esmx/router.svg" alt="node version" />
17
+ </a>
18
+ <a href="https://bundlephobia.com/package/@esmx/router">
19
+ <img src="https://img.shields.io/bundlephobia/minzip/@esmx/router" alt="size" />
20
+ </a>
21
+ </div>
22
+
23
+ <p>A universal, framework-agnostic router that works seamlessly with modern frontend frameworks</p>
24
+
25
+ <p>
26
+ English | <a href="https://github.com/esmnext/esmx/blob/master/packages/router/README.zh-CN.md">中文</a>
27
+ </p>
28
+ </div>
29
+
30
+ ## 🚀 Features
31
+
32
+ - **Framework Agnostic** - Works with any frontend framework (Vue, React, Preact, Solid, etc.)
33
+ - **Universal Support** - Runs in both browser and Node.js environments
34
+ - **TypeScript Ready** - Full TypeScript support with excellent type inference
35
+ - **High Performance** - Optimized for production use with minimal bundle size
36
+ - **SSR Compatible** - Complete SSR support
37
+ - **Modern API** - Clean and intuitive API design
38
+
39
+ ## 📦 Installation
40
+
41
+ ```bash
42
+ # npm
43
+ npm install @esmx/router
44
+
45
+ # pnpm
46
+ pnpm add @esmx/router
47
+
48
+ # yarn
49
+ yarn add @esmx/router
50
+ ```
51
+
52
+ ## 🚀 Quick Start
53
+
54
+ ```typescript
55
+ import { Router, RouterMode } from '@esmx/router';
56
+
57
+ // Create router instance
58
+ const router = new Router({
59
+ appId: 'app', // Application mount container ID (optional, defaults to 'app')
60
+ mode: RouterMode.history,
61
+ routes: [
62
+ { path: '/', component: () => 'Home Page' },
63
+ { path: '/about', component: () => 'About Page' }
64
+ ]
65
+ });
66
+
67
+ // Navigate to route
68
+ await router.push('/about');
69
+ ```
70
+
71
+ ## 📚 Documentation
72
+
73
+ Visit the [official documentation](https://esmx.dev) for detailed usage guides and API reference.
74
+
75
+ ### Route Navigation Flow
76
+
77
+ ```mermaid
78
+ flowchart TD
79
+ start(["Start"]):::Terminal --> normalizeURL["normalizeURL"]
80
+ normalizeURL --> isExternalUrl{"Internal URL"}:::Decision
81
+ isExternalUrl -- Yes --> matchInRouteTable["Match in route table"]
82
+ isExternalUrl -- No --> fallback["fallback"] --> End
83
+ matchInRouteTable --> isExist{"Match found"}:::Decision
84
+ isExist -- No --> fallback
85
+ isExist -- Yes --> execGuard["Execute hooks/guards"] --> End(["End"]):::Terminal
86
+ classDef Terminal fill:#FFF9C4,color:#000
87
+ classDef Decision fill:#C8E6C9,color:#000
88
+ ```
89
+
90
+ #### Route Hook Pipeline
91
+
92
+ | | fallback | override | beforeLeave | beforeEach | beforeUpdate | beforeEnter | asyncComponent | confirm |
93
+ |---------|----------|----------|-------------|------------|--------------|-------------|----------------|---------|
94
+ | `push` | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
95
+ | `replace` | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
96
+ | `pushWindow` | ✅ | ✅ | ❌ | ✅ | ❌ | ❌ | ❌ | ✅ |
97
+ | `pushLayer` | ✅ | ✅ | ❌ | ✅ | ❌ | ❌ | ❌ | ✅ |
98
+ | `replaceWindow` | ✅ | ✅ | ✅ | ✅ | ❌ | ❌ | ❌ | ✅ |
99
+ | `restartApp` | ✅ | ❌ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
100
+ | `unknown` | ✅ | ❌ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
101
+
102
+ ```mermaid
103
+ gantt
104
+ title Route Hook Execution Comparison
105
+ dateFormat X
106
+ axisFormat %s
107
+ section push\nreplace
108
+ fallback :0, 1
109
+ override :1, 2
110
+ beforeLeave :2, 3
111
+ beforeEach :3, 4
112
+ beforeUpdate :4, 5
113
+ beforeEnter :5, 6
114
+ asyncComponent:6, 7
115
+ confirm :7, 8
116
+ section pushWindow\npushLayer
117
+ fallback :0, 1
118
+ override :1, 2
119
+ beforeEach :3, 4
120
+ confirm :7, 8
121
+ section replaceWindow
122
+ fallback :0, 1
123
+ override :1, 2
124
+ beforeLeave :2, 3
125
+ beforeEach :3, 4
126
+ confirm :7, 8
127
+ section restartApp\nunknown
128
+ fallback :0, 1
129
+ beforeLeave :2, 3
130
+ beforeEach :3, 4
131
+ beforeUpdate :4, 5
132
+ beforeEnter :5, 6
133
+ asyncComponent:6, 7
134
+ confirm :7, 8
135
+ ```
136
+
137
+ #### Hook Functions
138
+
139
+ - **fallback**: Handle unmatched routes
140
+ - **override**: Allow route override logic
141
+ - **beforeLeave**: Execute before leaving current route
142
+ - **beforeEach**: Global navigation guard
143
+ - **beforeUpdate**: Execute before route update (same component)
144
+ - **beforeEnter**: Execute before entering new route
145
+ - **asyncComponent**: Load async component
146
+ - **confirm**: Final confirmation and navigation execution
147
+
148
+ #### Navigation Types
149
+
150
+ - **Standard Navigation** (`push`, `replace`): Execute full hook chain
151
+ - **Window Operations** (`pushWindow`, `replaceWindow`): Simplified hook chain for window-level navigation
152
+ - **Layer Operations** (`pushLayer`): Minimal hook chain for layer navigation
153
+ - **App Restart** (`restartApp`): Full hook chain but skip override
154
+ - **Unknown Type** (`unknown`): Full hook chain but skip override, used as default handling
155
+
156
+ ## 📄 License
157
+
158
+ MIT © [Esmx Team](https://github.com/esmnext/esmx)
@@ -0,0 +1,158 @@
1
+ <div align="center">
2
+ <img src="https://esmx.dev/logo.svg?t=2025" width="120" alt="Esmx Logo" />
3
+ <h1>@esmx/router</h1>
4
+
5
+ <div>
6
+ <a href="https://www.npmjs.com/package/@esmx/router">
7
+ <img src="https://img.shields.io/npm/v/@esmx/router.svg" alt="npm version" />
8
+ </a>
9
+ <a href="https://github.com/esmnext/esmx/actions/workflows/build.yml">
10
+ <img src="https://github.com/esmnext/esmx/actions/workflows/build.yml/badge.svg" alt="Build" />
11
+ </a>
12
+ <a href="https://esmx.dev/coverage/">
13
+ <img src="https://img.shields.io/badge/coverage-live%20report-brightgreen" alt="Coverage Report" />
14
+ </a>
15
+ <a href="https://nodejs.org/">
16
+ <img src="https://img.shields.io/node/v/@esmx/router.svg" alt="node version" />
17
+ </a>
18
+ <a href="https://bundlephobia.com/package/@esmx/router">
19
+ <img src="https://img.shields.io/bundlephobia/minzip/@esmx/router" alt="size" />
20
+ </a>
21
+ </div>
22
+
23
+ <p>通用的框架无关路由器,与现代前端框架无缝协作</p>
24
+
25
+ <p>
26
+ <a href="https://github.com/esmnext/esmx/blob/master/packages/router/README.md">English</a> | 中文
27
+ </p>
28
+ </div>
29
+
30
+ ## 🚀 特性
31
+
32
+ - **框架无关** - 适用于任何前端框架(Vue、React、Preact、Solid 等)
33
+ - **通用支持** - 在浏览器和 Node.js 环境中运行
34
+ - **TypeScript 支持** - 完整的 TypeScript 类型推断与类型安全
35
+ - **高性能** - 针对生产环境优化,极小的包体积
36
+ - **SSR 兼容** - 完整的 SSR 支持
37
+ - **现代 API** - 简洁直观的 API 设计
38
+
39
+ ## 📦 安装
40
+
41
+ ```bash
42
+ # npm
43
+ npm install @esmx/router
44
+
45
+ # pnpm
46
+ pnpm add @esmx/router
47
+
48
+ # yarn
49
+ yarn add @esmx/router
50
+ ```
51
+
52
+ ## 🚀 快速开始
53
+
54
+ ```typescript
55
+ import { Router, RouterMode } from '@esmx/router';
56
+
57
+ // 创建路由器实例
58
+ const router = new Router({
59
+ appId: 'app', // 应用挂载容器 ID(可选,默认 'app')
60
+ mode: RouterMode.history,
61
+ routes: [
62
+ { path: '/', component: () => '首页' },
63
+ { path: '/about', component: () => '关于页面' }
64
+ ]
65
+ });
66
+
67
+ // 导航到路由
68
+ await router.push('/about');
69
+ ```
70
+
71
+ ## 📚 文档
72
+
73
+ 访问[官方文档](https://esmx.dev)获取详细的使用指南和 API 参考。
74
+
75
+ ### 路由导航时大致的流程说明
76
+
77
+ ```mermaid
78
+ flowchart TD
79
+ start(["Start"]):::Terminal --> normalizeURL["normalizeURL"]
80
+ normalizeURL --> isExternalUrl{"是站内地址"}:::Decision
81
+ isExternalUrl -- Yes --> matchInRouteTable["在路由表内匹配"]
82
+ isExternalUrl -- No --> fallback["fallback"] --> End
83
+ matchInRouteTable --> isExist{"存在匹配项"}:::Decision
84
+ isExist -- No --> fallback
85
+ isExist -- Yes --> execGuard["执行其他回调钩子/守卫"] --> End(["End"]):::Terminal
86
+ classDef Terminal fill:#FFF9C4,color:#000
87
+ classDef Decision fill:#C8E6C9,color:#000
88
+ ```
89
+
90
+ #### 路由钩子管道
91
+
92
+ | | fallback | override | beforeLeave | beforeEach | beforeUpdate | beforeEnter | asyncComponent | confirm |
93
+ |---------|----------|----------|-------------|------------|--------------|-------------|----------------|---------|
94
+ | `push` | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
95
+ | `replace` | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
96
+ | `pushWindow` | ✅ | ✅ | ❌ | ✅ | ❌ | ❌ | ❌ | ✅ |
97
+ | `pushLayer` | ✅ | ✅ | ❌ | ✅ | ❌ | ❌ | ❌ | ✅ |
98
+ | `replaceWindow` | ✅ | ✅ | ✅ | ✅ | ❌ | ❌ | ❌ | ✅ |
99
+ | `restartApp` | ✅ | ❌ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
100
+ | `unknown` | ✅ | ❌ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
101
+
102
+ ```mermaid
103
+ gantt
104
+ title 路由钩子执行对比
105
+ dateFormat X
106
+ axisFormat %s
107
+ section push<br>replace
108
+ fallback :0, 1
109
+ override :1, 2
110
+ beforeLeave :2, 3
111
+ beforeEach :3, 4
112
+ beforeUpdate :4, 5
113
+ beforeEnter :5, 6
114
+ asyncComponent:6, 7
115
+ confirm :7, 8
116
+ section pushWindow<br>pushLayer
117
+ fallback :0, 1
118
+ override :1, 2
119
+ beforeEach :3, 4
120
+ confirm :7, 8
121
+ section replaceWindow
122
+ fallback :0, 1
123
+ override :1, 2
124
+ beforeLeave :2, 3
125
+ beforeEach :3, 4
126
+ confirm :7, 8
127
+ section restartApp<br>unknown
128
+ fallback :0, 1
129
+ beforeLeave :2, 3
130
+ beforeEach :3, 4
131
+ beforeUpdate :4, 5
132
+ beforeEnter :5, 6
133
+ asyncComponent:6, 7
134
+ confirm :7, 8
135
+ ```
136
+
137
+ #### 钩子函数说明
138
+
139
+ - **fallback**: 处理未匹配的路由
140
+ - **override**: 允许路由重写逻辑
141
+ - **beforeLeave**: 离开当前路由前执行
142
+ - **beforeEach**: 全局导航守卫
143
+ - **beforeUpdate**: 路由更新前执行(相同组件)
144
+ - **beforeEnter**: 进入新路由前执行
145
+ - **asyncComponent**: 加载异步组件
146
+ - **confirm**: 最终确认和导航执行
147
+
148
+ #### 路由类型特点
149
+
150
+ - **标准导航** (`push`、`replace`): 执行完整的钩子链
151
+ - **窗口操作** (`pushWindow`、`replaceWindow`): 简化的钩子链,主要用于窗口级别的导航
152
+ - **层级操作** (`pushLayer`): 最简化的钩子链,用于层级导航
153
+ - **应用重启** (`restartApp`): 完整钩子链但跳过 override
154
+ - **未知类型** (`unknown`): 完整钩子链但跳过 override,作为默认处理
155
+
156
+ ## 📄 许可证
157
+
158
+ MIT © [Esmx Team](https://github.com/esmnext/esmx)
@@ -0,0 +1,23 @@
1
+ import type { Route } from './route';
2
+ export declare class RouteError extends Error {
3
+ readonly code: string;
4
+ readonly to: Route;
5
+ readonly from: Route | null;
6
+ constructor(message: string, code: string, to: Route, from?: Route | null);
7
+ }
8
+ export declare class RouteTaskCancelledError extends RouteError {
9
+ readonly taskName: string;
10
+ constructor(taskName: string, to: Route, from?: Route | null);
11
+ }
12
+ export declare class RouteTaskExecutionError extends RouteError {
13
+ readonly taskName: string;
14
+ readonly originalError: Error;
15
+ constructor(taskName: string, to: Route, from?: Route | null, originalError?: unknown);
16
+ }
17
+ export declare class RouteNavigationAbortedError extends RouteError {
18
+ readonly taskName: string;
19
+ constructor(taskName: string, to: Route, from?: Route | null);
20
+ }
21
+ export declare class RouteSelfRedirectionError extends RouteError {
22
+ constructor(fullPath: string, to: Route, from?: Route | null);
23
+ }
package/dist/error.mjs ADDED
@@ -0,0 +1,64 @@
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);
4
+ export class RouteError extends Error {
5
+ constructor(message, code, to, from = null) {
6
+ super(message);
7
+ __publicField(this, "code");
8
+ __publicField(this, "to");
9
+ __publicField(this, "from");
10
+ this.name = "RouteError";
11
+ this.code = code;
12
+ this.to = to;
13
+ this.from = from;
14
+ }
15
+ }
16
+ export class RouteTaskCancelledError extends RouteError {
17
+ constructor(taskName, to, from = null) {
18
+ super(
19
+ 'Route task "'.concat(taskName, '" was cancelled'),
20
+ "ROUTE_TASK_CANCELLED",
21
+ to,
22
+ from
23
+ );
24
+ __publicField(this, "taskName");
25
+ this.name = "RouteTaskCancelledError";
26
+ this.taskName = taskName;
27
+ }
28
+ }
29
+ export class RouteTaskExecutionError extends RouteError {
30
+ constructor(taskName, to, from = null, originalError) {
31
+ const error = originalError instanceof Error ? originalError : new Error(String(originalError));
32
+ const message = 'Route task "'.concat(taskName, '" failed').concat(error.message ? ": ".concat(error.message) : "");
33
+ super(message, "ROUTE_TASK_EXECUTION_ERROR", to, from);
34
+ __publicField(this, "taskName");
35
+ __publicField(this, "originalError");
36
+ this.name = "RouteTaskExecutionError";
37
+ this.taskName = taskName;
38
+ this.originalError = error;
39
+ }
40
+ }
41
+ export class RouteNavigationAbortedError extends RouteError {
42
+ constructor(taskName, to, from = null) {
43
+ super(
44
+ 'Navigation was aborted by task "'.concat(taskName, '"'),
45
+ "ROUTE_NAVIGATION_ABORTED",
46
+ to,
47
+ from
48
+ );
49
+ __publicField(this, "taskName");
50
+ this.name = "RouteNavigationAbortedError";
51
+ this.taskName = taskName;
52
+ }
53
+ }
54
+ export class RouteSelfRedirectionError extends RouteError {
55
+ constructor(fullPath, to, from = null) {
56
+ super(
57
+ 'Detected a self-redirection to "'.concat(fullPath, '". Aborting navigation.'),
58
+ "ROUTE_SELF_REDIRECTION",
59
+ to,
60
+ from
61
+ );
62
+ this.name = "RouteSelfRedirectionError";
63
+ }
64
+ }
@@ -0,0 +1,7 @@
1
+ export declare class IncrementId {
2
+ private value;
3
+ equal(id: number): boolean;
4
+ next(): number;
5
+ }
6
+ export declare const PAGE_ID: IncrementId;
7
+ export declare const LAYER_ID: IncrementId;
@@ -0,0 +1,16 @@
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);
4
+ export class IncrementId {
5
+ constructor() {
6
+ __publicField(this, "value", 0);
7
+ }
8
+ equal(id) {
9
+ return this.value === id;
10
+ }
11
+ next() {
12
+ return ++this.value;
13
+ }
14
+ }
15
+ export const PAGE_ID = new IncrementId();
16
+ export const LAYER_ID = new IncrementId();
package/dist/index.d.ts CHANGED
@@ -1,3 +1,14 @@
1
- export { createRouter } from './router';
2
- export * from './types';
3
- export * from './utils';
1
+ export { RouteError, RouteNavigationAbortedError, RouteSelfRedirectionError, RouteTaskCancelledError, RouteTaskExecutionError } from './error';
2
+ export { Route } from './route';
3
+ export { Router } from './router';
4
+ export { type RouteConfig, type RouteConfirmHook, type RouteConfirmHookResult, type RouteHandleHook, type RouteHandleResult, type RouteLayerOptions, type RouteLayerResult, type RouteLocation, type RouteLocationInput, type RouteMatcher, type RouteMatchResult, type RouteMatchType, type RouteMeta, type RouteNotifyHook, type RouteOptions, type RouteParsedConfig, type RouterLayerOptions, type RouterLinkAttributes, type RouterLinkProps, type RouterLinkResolved, type RouterLinkType, type RouterMicroApp, type RouterMicroAppCallback, type RouterMicroAppOptions, RouterMode, type RouterOptions, type RouterParsedOptions, type RouteState, RouteType, type RouteVerifyHook } from './types';
5
+ import type { Router } from './router';
6
+ import type { Route, RouteLocation, RouteLocationInput } from './types';
7
+ /** @deprecated Use `Router` directly instead of `RouterInstance`. */
8
+ export type RouterInstance = Router;
9
+ /** @deprecated Use `RouteLocationInput` directly instead of `RouterRawLocation`. */
10
+ export type RouterRawLocation = RouteLocationInput;
11
+ /** @deprecated Use `RouteLocation` directly instead of `RouterLocation`. */
12
+ export type RouterLocation = RouteLocation;
13
+ /** @deprecated Use `Route` directly instead of `RouteRecord`. */
14
+ export type RouteRecord = Route;
package/dist/index.mjs CHANGED
@@ -1,3 +1,13 @@
1
- export { createRouter } from "./router.mjs";
2
- export * from "./types";
3
- export * from "./utils/index.mjs";
1
+ export {
2
+ RouteError,
3
+ RouteNavigationAbortedError,
4
+ RouteSelfRedirectionError,
5
+ RouteTaskCancelledError,
6
+ RouteTaskExecutionError
7
+ } from "./error.mjs";
8
+ export { Route } from "./route.mjs";
9
+ export { Router } from "./router.mjs";
10
+ export {
11
+ RouterMode,
12
+ RouteType
13
+ } from "./types.mjs";
@@ -0,0 +1,22 @@
1
+ import type { RouteLocation, RouteLocationInput } from './types';
2
+ /**
3
+ * Normalizes a URL input into a URL object.
4
+ * @param url - The URL or string to normalize.
5
+ * @param base - The base URL to resolve against if the input is relative.
6
+ * @returns A URL object.
7
+ */
8
+ export declare function normalizeURL(url: string | URL, base: URL): URL;
9
+ /**
10
+ * Parses a RouteLocationInput object into a full URL.
11
+ * @param toInput - The route location input.
12
+ * @param baseURL - The base URL to resolve against.
13
+ * @returns The parsed URL object.
14
+ */
15
+ export declare function parseLocation(toInput: RouteLocationInput, baseURL: URL): URL;
16
+ /**
17
+ * Resolves RouteLocationInput with fallback from previous route
18
+ * @param toInput - The route location input
19
+ * @param from - The previous route URL (optional)
20
+ * @returns Resolved RouteLocation object
21
+ */
22
+ export declare function resolveRouteLocationInput(toInput?: RouteLocationInput, from?: URL | null): RouteLocation;
@@ -0,0 +1,64 @@
1
+ import { isNotNullish } from "./util.mjs";
2
+ export function normalizeURL(url, base) {
3
+ if (url instanceof URL) {
4
+ return url;
5
+ }
6
+ if (url.startsWith("//")) {
7
+ const protocol = base.protocol;
8
+ return new URL("".concat(protocol).concat(url));
9
+ }
10
+ if (url.startsWith("/")) {
11
+ const newBase = new URL(".", base);
12
+ const parsed = new URL(url, newBase);
13
+ parsed.pathname = newBase.pathname.slice(0, -1) + parsed.pathname;
14
+ return parsed;
15
+ }
16
+ try {
17
+ return new URL(url);
18
+ } catch (e) {
19
+ return new URL(url, base);
20
+ }
21
+ }
22
+ export function parseLocation(toInput, baseURL) {
23
+ var _a, _b;
24
+ if (typeof toInput === "string") {
25
+ return normalizeURL(toInput, baseURL);
26
+ }
27
+ const url = normalizeURL((_b = (_a = toInput.path) != null ? _a : toInput.url) != null ? _b : "", baseURL);
28
+ const searchParams = url.searchParams;
29
+ const mergedQuery = {};
30
+ if (toInput.query) {
31
+ Object.entries(toInput.query).forEach(([key, value]) => {
32
+ if (typeof value !== "undefined") {
33
+ mergedQuery[key] = value;
34
+ }
35
+ });
36
+ }
37
+ if (toInput.queryArray) {
38
+ Object.entries(toInput.queryArray).forEach(([key, value]) => {
39
+ if (typeof value !== "undefined") {
40
+ mergedQuery[key] = value;
41
+ }
42
+ });
43
+ }
44
+ Object.entries(mergedQuery).forEach(([key, value]) => {
45
+ searchParams.delete(key);
46
+ value = Array.isArray(value) ? value : [value];
47
+ value.filter((v) => isNotNullish(v) && !Number.isNaN(v)).forEach((v) => {
48
+ searchParams.append(key, String(v));
49
+ });
50
+ });
51
+ if (toInput.hash) {
52
+ url.hash = toInput.hash;
53
+ }
54
+ return url;
55
+ }
56
+ export function resolveRouteLocationInput(toInput = "/", from = null) {
57
+ if (typeof toInput === "string") {
58
+ return { path: toInput };
59
+ }
60
+ if (toInput && typeof toInput === "object" && typeof toInput.path !== "string" && typeof toInput.url !== "string" && from !== null) {
61
+ return { ...toInput, url: from.href };
62
+ }
63
+ return toInput;
64
+ }
@@ -0,0 +1,4 @@
1
+ import type { RouteConfig, RouteMatcher, RouteParsedConfig } from './types';
2
+ export declare function createMatcher(routes: RouteConfig[], compiledRoutes?: RouteParsedConfig[]): RouteMatcher;
3
+ export declare function createRouteMatches(routes: RouteConfig[], base?: string): RouteParsedConfig[];
4
+ export declare function joinPathname(pathname: string, base?: string): string;
@@ -0,0 +1,49 @@
1
+ import { compile, match } from "path-to-regexp";
2
+ export function createMatcher(routes, compiledRoutes = createRouteMatches(routes)) {
3
+ return (toURL, baseURL, cb) => {
4
+ const matchPath = toURL.pathname.substring(baseURL.pathname.length - 1);
5
+ const matches = [];
6
+ const params = {};
7
+ const collectMatchingRoutes = (routes2) => {
8
+ for (const item of routes2) {
9
+ if (cb && !cb(item)) {
10
+ continue;
11
+ }
12
+ if (item.children.length && collectMatchingRoutes(item.children)) {
13
+ matches.unshift(item);
14
+ return true;
15
+ }
16
+ if (item.requireIndex && item.children.length) continue;
17
+ const result = item.match(matchPath);
18
+ if (result) {
19
+ matches.unshift(item);
20
+ if (typeof result === "object") {
21
+ Object.assign(params, result.params);
22
+ }
23
+ return true;
24
+ }
25
+ }
26
+ return false;
27
+ };
28
+ collectMatchingRoutes(compiledRoutes);
29
+ return { matches: Object.freeze(matches), params };
30
+ };
31
+ }
32
+ export function createRouteMatches(routes, base = "") {
33
+ return routes.map((route) => {
34
+ var _a;
35
+ const compilePath = joinPathname(route.path, base);
36
+ return {
37
+ ...route,
38
+ compilePath,
39
+ match: match(compilePath),
40
+ compile: compile(compilePath),
41
+ meta: route.meta || {},
42
+ requireIndex: (_a = route.requireIndex) != null ? _a : false,
43
+ children: Array.isArray(route.children) ? createRouteMatches(route.children, compilePath) : []
44
+ };
45
+ });
46
+ }
47
+ export function joinPathname(pathname, base = "") {
48
+ return "/" + "".concat(base, "/").concat(pathname).split("/").filter(Boolean).join("/");
49
+ }
@@ -0,0 +1,20 @@
1
+ import type { Router } from './router';
2
+ import type { RouterMicroAppOptions } from './types';
3
+ /**
4
+ * Gets the root container element by ID.
5
+ * If not found, creates a new div with the given ID and appends it to document.body.
6
+ *
7
+ * @param appId - The application container ID.
8
+ * @returns The resolved HTMLElement.
9
+ */
10
+ export declare function getRootElement(appId: string): HTMLElement;
11
+ export declare class MicroApp {
12
+ app: RouterMicroAppOptions | null;
13
+ root: HTMLElement | null;
14
+ private _factory;
15
+ private destroyed;
16
+ _update(router: Router, force?: boolean): void;
17
+ private _getNextFactory;
18
+ destroy(): void;
19
+ private _clearRoot;
20
+ }