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

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 (106) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +158 -0
  3. package/README.zh-CN.md +158 -0
  4. package/dist/error.d.ts +23 -0
  5. package/dist/error.mjs +64 -0
  6. package/dist/increment-id.d.ts +7 -0
  7. package/dist/increment-id.mjs +16 -0
  8. package/dist/index.d.ts +14 -3
  9. package/dist/index.mjs +13 -3
  10. package/dist/location.d.ts +22 -0
  11. package/dist/location.mjs +64 -0
  12. package/dist/matcher.d.ts +4 -0
  13. package/dist/matcher.mjs +49 -0
  14. package/dist/micro-app.d.ts +20 -0
  15. package/dist/micro-app.mjs +132 -0
  16. package/dist/navigation.d.ts +45 -0
  17. package/dist/navigation.mjs +153 -0
  18. package/dist/options.d.ts +4 -0
  19. package/dist/options.mjs +95 -0
  20. package/dist/route-task.d.ts +40 -0
  21. package/dist/route-task.mjs +77 -0
  22. package/dist/route-transition.d.ts +54 -0
  23. package/dist/route-transition.mjs +362 -0
  24. package/dist/route.d.ts +77 -0
  25. package/dist/route.mjs +223 -0
  26. package/dist/router-link.d.ts +10 -0
  27. package/dist/router-link.mjs +142 -0
  28. package/dist/router.d.ts +113 -102
  29. package/dist/router.mjs +321 -354
  30. package/dist/scroll.d.ts +33 -0
  31. package/dist/scroll.mjs +50 -0
  32. package/dist/types.d.ts +312 -0
  33. package/dist/types.mjs +18 -0
  34. package/dist/util.d.ts +32 -0
  35. package/dist/util.mjs +100 -0
  36. package/package.json +89 -62
  37. package/src/error.ts +84 -0
  38. package/src/increment-id.ts +12 -0
  39. package/src/index.ts +67 -3
  40. package/src/location.ts +124 -0
  41. package/src/matcher.ts +71 -0
  42. package/src/micro-app.ts +153 -0
  43. package/src/navigation.ts +202 -0
  44. package/src/options.ts +136 -0
  45. package/src/route-task.ts +102 -0
  46. package/src/route-transition.ts +480 -0
  47. package/src/route.ts +335 -0
  48. package/src/router-link.ts +241 -0
  49. package/src/router.ts +351 -467
  50. package/src/scroll.ts +106 -0
  51. package/src/types.ts +415 -0
  52. package/src/util.ts +184 -0
  53. package/dist/history/abstract.d.ts +0 -29
  54. package/dist/history/abstract.mjs +0 -107
  55. package/dist/history/base.d.ts +0 -79
  56. package/dist/history/base.mjs +0 -275
  57. package/dist/history/html.d.ts +0 -22
  58. package/dist/history/html.mjs +0 -181
  59. package/dist/history/index.d.ts +0 -7
  60. package/dist/history/index.mjs +0 -16
  61. package/dist/matcher/create-matcher.d.ts +0 -5
  62. package/dist/matcher/create-matcher.mjs +0 -218
  63. package/dist/matcher/create-matcher.spec.d.ts +0 -1
  64. package/dist/matcher/create-matcher.spec.mjs +0 -0
  65. package/dist/matcher/index.d.ts +0 -1
  66. package/dist/matcher/index.mjs +0 -1
  67. package/dist/task-pipe/index.d.ts +0 -1
  68. package/dist/task-pipe/index.mjs +0 -1
  69. package/dist/task-pipe/task.d.ts +0 -30
  70. package/dist/task-pipe/task.mjs +0 -66
  71. package/dist/utils/bom.d.ts +0 -5
  72. package/dist/utils/bom.mjs +0 -10
  73. package/dist/utils/encoding.d.ts +0 -48
  74. package/dist/utils/encoding.mjs +0 -44
  75. package/dist/utils/guards.d.ts +0 -9
  76. package/dist/utils/guards.mjs +0 -12
  77. package/dist/utils/index.d.ts +0 -7
  78. package/dist/utils/index.mjs +0 -27
  79. package/dist/utils/path.d.ts +0 -60
  80. package/dist/utils/path.mjs +0 -264
  81. package/dist/utils/path.spec.d.ts +0 -1
  82. package/dist/utils/path.spec.mjs +0 -30
  83. package/dist/utils/scroll.d.ts +0 -25
  84. package/dist/utils/scroll.mjs +0 -59
  85. package/dist/utils/utils.d.ts +0 -16
  86. package/dist/utils/utils.mjs +0 -11
  87. package/dist/utils/warn.d.ts +0 -2
  88. package/dist/utils/warn.mjs +0 -12
  89. package/src/history/abstract.ts +0 -149
  90. package/src/history/base.ts +0 -408
  91. package/src/history/html.ts +0 -231
  92. package/src/history/index.ts +0 -20
  93. package/src/matcher/create-matcher.spec.ts +0 -3
  94. package/src/matcher/create-matcher.ts +0 -293
  95. package/src/matcher/index.ts +0 -1
  96. package/src/task-pipe/index.ts +0 -1
  97. package/src/task-pipe/task.ts +0 -97
  98. package/src/utils/bom.ts +0 -14
  99. package/src/utils/encoding.ts +0 -153
  100. package/src/utils/guards.ts +0 -25
  101. package/src/utils/index.ts +0 -27
  102. package/src/utils/path.spec.ts +0 -44
  103. package/src/utils/path.ts +0 -397
  104. package/src/utils/scroll.ts +0 -120
  105. package/src/utils/utils.ts +0 -30
  106. package/src/utils/warn.ts +0 -13
package/dist/router.mjs CHANGED
@@ -1,399 +1,366 @@
1
- import URLParse from "url-parse";
2
- import { createHistory } from "./history/index.mjs";
3
- import { createRouterMatcher } from "./matcher/index.mjs";
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
+ import { LAYER_ID } from "./increment-id.mjs";
5
+ import { MicroApp } from "./micro-app.mjs";
6
+ import { Navigation } from "./navigation.mjs";
7
+ import { parsedOptions } from "./options.mjs";
8
+ import { Route } from "./route.mjs";
9
+ import { RouteTransition } from "./route-transition.mjs";
10
+ import { createLinkResolver } from "./router-link.mjs";
11
+ import { RouterMode, RouteType } from "./types.mjs";
4
12
  import {
5
- RouterMode,
6
- StateLayerConfigKey
7
- } from "./types";
8
- import { inBrowser, normalizePath, regexDomain } from "./utils/index.mjs";
9
- const baseValue = Number(Date.now());
10
- let layerIdOffset = 0;
11
- function getLatestLayerId() {
12
- return baseValue + ++layerIdOffset;
13
- }
13
+ isNotNullish,
14
+ isPlainObject,
15
+ isRouteMatched,
16
+ validateSsrRootElement
17
+ } from "./util.mjs";
18
+ const LAYER_SKIP_TYPES = /* @__PURE__ */ new Set([
19
+ RouteType.pushWindow,
20
+ RouteType.replaceWindow,
21
+ RouteType.replace,
22
+ RouteType.restartApp,
23
+ RouteType.pushLayer
24
+ ]);
14
25
  export class Router {
15
- /**
16
- * 当前路由对象的上级路由对象
17
- */
18
- parent = null;
19
- /* 路由配置 */
20
- options;
21
- /**
22
- * 路由固定前置路径
23
- * 需要注意的是如果使用函数返回 base,需要尽量保证相同的路径返回相同base
24
- */
25
- base;
26
- /* 路由模式 */
27
- mode;
28
- /* 路由匹配器 */
29
- matcher;
30
- /* 路由history类 */
31
- history;
32
- /* 滚动行为 */
33
- scrollBehavior;
34
- /* 当前路由信息 */
35
- route = {
36
- href: "",
37
- origin: "",
38
- host: "",
39
- protocol: "",
40
- hostname: "",
41
- port: "",
42
- pathname: "",
43
- search: "",
44
- hash: "",
45
- params: {},
46
- query: {},
47
- queryArray: {},
48
- state: {},
49
- meta: {},
50
- base: "",
51
- path: "",
52
- fullPath: "",
53
- matched: []
54
- };
55
26
  constructor(options) {
27
+ __publicField(this, "options");
28
+ __publicField(this, "parsedOptions");
29
+ __publicField(this, "isLayer");
30
+ __publicField(this, "navigation");
31
+ __publicField(this, "microApp", new MicroApp());
32
+ // Route transition manager
33
+ __publicField(this, "transition", new RouteTransition(this));
56
34
  this.options = options;
57
- this.matcher = createRouterMatcher(options.routes || []);
58
- this.mode = options.mode || (inBrowser ? RouterMode.HISTORY : RouterMode.ABSTRACT);
59
- this.base = options.base || "";
60
- this.scrollBehavior = options.scrollBehavior || ((to, from, savedPosition) => {
61
- if (savedPosition) return savedPosition;
62
- return {
63
- left: 0,
64
- top: 0
65
- };
66
- });
67
- this.history = createHistory({
68
- router: this,
69
- mode: this.mode
70
- });
71
- }
72
- /* 更新路由 */
73
- updateRoute(route) {
74
- var _a, _b, _c, _d, _e, _f;
75
- const curAppType = (_b = (_a = this.route) == null ? void 0 : _a.matched[0]) == null ? void 0 : _b.appType;
76
- const appType = (_c = route.matched[0]) == null ? void 0 : _c.appType;
77
- this.applyRoute(route);
78
- const curRegisterConfig = curAppType && this.registeredConfigMap[curAppType];
79
- const registerConfig = appType && this.registeredConfigMap[appType];
80
- if (registerConfig) {
81
- const { mounted, generator } = registerConfig;
82
- if (!mounted) {
83
- registerConfig.config = generator(this);
84
- (_d = registerConfig.config) == null ? void 0 : _d.mount();
85
- registerConfig.mounted = true;
86
- this.layerMap[this.layerId] = {
87
- router: this,
88
- config: registerConfig.config,
89
- destroyed: false
90
- };
91
- if (!this.layerConfigList.find(
92
- (item) => item.id === this.layerId
93
- )) {
94
- this.layerConfigList.push({
95
- id: this.layerId,
96
- depth: 0
97
- });
98
- }
35
+ this.parsedOptions = parsedOptions(options);
36
+ this.isLayer = this.parsedOptions.layer;
37
+ this.navigation = new Navigation(
38
+ this.parsedOptions,
39
+ (url, state) => {
40
+ this.transition.to(RouteType.unknown, {
41
+ url,
42
+ state
43
+ });
99
44
  }
100
- (_e = registerConfig.config) == null ? void 0 : _e.updated();
101
- }
102
- if (curAppType !== appType && curRegisterConfig) {
103
- (_f = curRegisterConfig.config) == null ? void 0 : _f.destroy();
104
- curRegisterConfig.mounted = false;
105
- }
45
+ );
106
46
  }
107
- /* 应用路由 */
108
- applyRoute(route) {
109
- let url = "";
110
- const { fullPath } = route;
111
- if (inBrowser && !regexDomain.test(fullPath)) {
112
- url = normalizePath(fullPath, location.origin);
113
- } else {
114
- url = normalizePath(fullPath);
47
+ get route() {
48
+ const route = this.transition.route;
49
+ if (route === null) {
50
+ throw new Error(
51
+ "No active route found. Please navigate to a route first using router.push() or router.replace()."
52
+ );
115
53
  }
116
- const {
117
- hash,
118
- host,
119
- hostname,
120
- href,
121
- origin,
122
- pathname,
123
- port,
124
- protocol,
125
- query
126
- } = new URLParse(url);
127
- Object.assign(
128
- this.route,
129
- {
130
- href,
131
- origin,
132
- host,
133
- protocol,
134
- hostname,
135
- port,
136
- pathname,
137
- search: query,
138
- hash
139
- },
140
- route
141
- );
54
+ return route;
142
55
  }
143
- /* 解析路由 */
144
- resolve(location2) {
145
- return this.history.resolve(location2);
56
+ get context() {
57
+ return this.parsedOptions.context;
146
58
  }
147
- /**
148
- * 新增单个路由匹配规则
149
- */
150
- // addRoutes(routes: RouteConfig[]) {
151
- // this.matcher.addRoutes(routes);
152
- // }
153
- /**
154
- * 新增多个路由匹配规则
155
- */
156
- // addRoute(route: RouteConfig): void {
157
- // this.matcher.addRoute(route);
158
- // }
159
- /* 初始化 */
160
- async init(options = {}) {
59
+ get data() {
60
+ return this.parsedOptions.data;
61
+ }
62
+ get appId() {
63
+ return this.parsedOptions.appId;
64
+ }
65
+ get mode() {
66
+ return this.parsedOptions.mode;
67
+ }
68
+ get base() {
69
+ return this.parsedOptions.base;
70
+ }
71
+ get req() {
161
72
  var _a;
162
- const { parent = null, route, replace = true } = options;
163
- await this.history.init({
164
- replace
165
- });
166
- const layerId = getLatestLayerId();
167
- this.layerId = layerId;
168
- let layerMap = {};
169
- let layerConfigList = [];
170
- if (parent && route) {
171
- const appType = (_a = route.matched[0]) == null ? void 0 : _a.appType;
172
- if (!appType) return;
173
- const registerConfig = parent.registeredConfigMap[appType];
174
- if (!registerConfig) return;
175
- parent.freeze();
176
- this.registeredConfigMap = parent.registeredConfigMap;
177
- const { generator } = registerConfig;
178
- const config = generator(this);
179
- config.mount();
180
- config.updated();
181
- layerMap = parent.layerMap;
182
- layerMap[layerId] = {
183
- router: this,
184
- config,
185
- destroyed: false
186
- };
187
- layerConfigList = parent.layerConfigList;
188
- }
189
- if (!layerConfigList.find((item) => item.id === layerId)) {
190
- layerConfigList.push({
191
- id: layerId,
192
- depth: 0
193
- });
194
- }
195
- this.parent = parent;
196
- this.layerMap = layerMap;
197
- this.layerConfigList = layerConfigList;
73
+ return (_a = this.parsedOptions.req) != null ? _a : null;
198
74
  }
199
- /**
200
- * 卸载方法
201
- */
202
- async destroy() {
75
+ get res() {
76
+ var _a;
77
+ return (_a = this.parsedOptions.res) != null ? _a : null;
203
78
  }
204
- /* 已注册的app配置 */
205
- registeredConfigMap = {};
206
- /* app配置注册 */
207
- register(name, config) {
208
- this.registeredConfigMap[name] = {
209
- generator: config,
210
- mounted: false
211
- };
79
+ push(toInput) {
80
+ return this.transition.to(RouteType.push, toInput);
212
81
  }
213
- /* 全局路由守卫 */
214
- guards = {
215
- beforeEach: [],
216
- afterEach: []
217
- };
218
- /* 注册全局路由前置守卫 */
219
- beforeEach(guard) {
220
- this.guards.beforeEach.push(guard);
82
+ replace(toInput) {
83
+ return this.transition.to(RouteType.replace, toInput);
221
84
  }
222
- /* 卸载全局路由前置守卫 */
223
- unBindBeforeEach(guard) {
224
- const i = this.guards.beforeEach.findIndex((item) => item === guard);
225
- this.guards.beforeEach.splice(i, 1);
85
+ pushWindow(toInput) {
86
+ return this.transition.to(RouteType.pushWindow, toInput);
226
87
  }
227
- /* 注册全局路由后置守卫 */
228
- afterEach(guard) {
229
- this.guards.afterEach.push(guard);
88
+ replaceWindow(toInput) {
89
+ return this.transition.to(RouteType.replaceWindow, toInput);
230
90
  }
231
- /* 卸载全局路由后置守卫 */
232
- unBindAfterEach(guard) {
233
- const i = this.guards.afterEach.findIndex((item) => item === guard);
234
- this.guards.afterEach.splice(i, 1);
91
+ restartApp(toInput) {
92
+ return this.transition.to(
93
+ RouteType.restartApp,
94
+ toInput != null ? toInput : this.route.url.href
95
+ );
235
96
  }
236
- /* 路由跳转方法,会创建新的历史记录 */
237
- async push(location2) {
238
- await this.history.push(location2);
97
+ async back() {
98
+ const result = await this.navigation.go(-1);
99
+ if (result === null) {
100
+ this.parsedOptions.handleBackBoundary(this);
101
+ return null;
102
+ }
103
+ return this.transition.to(RouteType.back, {
104
+ url: result.url,
105
+ state: result.state
106
+ });
239
107
  }
240
- /* 路由跳转方法,会替换当前的历史记录 */
241
- async replace(location2) {
242
- await this.history.replace(location2);
108
+ async go(index) {
109
+ if (index === 0) return null;
110
+ const result = await this.navigation.go(index);
111
+ if (result === null) {
112
+ if (index < 0) {
113
+ this.parsedOptions.handleBackBoundary(this);
114
+ }
115
+ return null;
116
+ }
117
+ return this.transition.to(RouteType.go, {
118
+ url: result.url,
119
+ state: result.state
120
+ });
243
121
  }
244
- /**
245
- * 当前路由弹层id,用于区分不同的路由弹层
246
- */
247
- layerId = 0;
248
- /**
249
- * 路由弹层配置
250
- * key为路由弹层id
251
- */
252
- layerConfigList = [];
253
- /**
254
- * 路由弹层id与路由实例的map
255
- */
256
- layerMap = {};
257
- /**
258
- * 路由是否冻结
259
- */
260
- isFrozen = false;
261
- /**
262
- * 路由冻结方法
263
- */
264
- freeze() {
265
- this.isFrozen = true;
122
+ async forward() {
123
+ const result = await this.navigation.go(1);
124
+ if (result === null) return null;
125
+ return this.transition.to(RouteType.forward, {
126
+ url: result.url,
127
+ state: result.state
128
+ });
266
129
  }
267
130
  /**
268
- * 路由解冻方法
131
+ * Parse route location without performing actual navigation
132
+ *
133
+ * This method is used to parse route configuration and return the corresponding route object,
134
+ * but does not trigger actual page navigation. It is mainly used for the following scenarios:
135
+ * - Generate link URLs without jumping
136
+ * - Pre-check route matching
137
+ * - Get route parameters, meta information, etc.
138
+ * - Test the validity of route configuration
139
+ *
140
+ * @param toInput Target route location, can be a string path or route configuration object
141
+ * @returns Parsed route object containing complete route information
142
+ *
143
+ * @example
144
+ * ```typescript
145
+ * // Parse string path
146
+ * const route = router.resolve('/user/123');
147
+ * const url = route.url.href; // Get complete URL
148
+ *
149
+ * // Parse named route
150
+ * const userRoute = router.resolve({
151
+ * name: 'user',
152
+ * params: { id: '123' }
153
+ * });
154
+ * console.log(userRoute.params.id); // '123'
155
+ *
156
+ * // Check route validity
157
+ * const testRoute = router.resolve('/some/path');
158
+ * if (testRoute.matched.length > 0) {
159
+ * // Route matched successfully
160
+ * }
161
+ * ```
269
162
  */
270
- unfreeze() {
271
- this.isFrozen = false;
163
+ resolve(toInput, toType) {
164
+ var _a, _b;
165
+ return new Route({
166
+ options: this.parsedOptions,
167
+ toType,
168
+ toInput,
169
+ from: (_b = (_a = this.transition.route) == null ? void 0 : _a.url) != null ? _b : null
170
+ });
272
171
  }
273
172
  /**
274
- * 打开路由弹层方法,会创建新的路由实例并调用注册的 register 方法
275
- * 服务端会使用 push 作为替代
173
+ * Check if the route matches the current route
174
+ *
175
+ * @param toRoute Target route object to compare
176
+ * @param matchType Match type
177
+ * - 'route': Route-level matching, compare if route configurations are the same
178
+ * - 'exact': Exact matching, compare if paths are completely the same
179
+ * - 'include': Include matching, check if current path contains target path
180
+ * @returns Whether it matches
276
181
  */
277
- async pushLayer(location2) {
278
- if (this.isFrozen) return;
279
- const route = this.resolve(location2);
280
- if (route.fullPath === this.route.fullPath) return;
281
- if (!inBrowser) {
282
- this.push(location2);
283
- return;
284
- }
285
- const router = createRouter({
286
- ...this.options,
287
- initUrl: route.fullPath
288
- });
289
- await router.init({ parent: this, route, replace: false });
182
+ isRouteMatched(toRoute, matchType = "include") {
183
+ const currentRoute = this.transition.route;
184
+ if (!currentRoute) return false;
185
+ return isRouteMatched(currentRoute, toRoute, matchType);
290
186
  }
291
187
  /**
292
- * 更新路由弹层方法
293
- * @param state 参数为history.state
294
- * @description 没有传入 state 时使用当前配置更新 history.state,传入了 state 时使用传入的 state 更新当前配置
188
+ * Resolve router link configuration and return complete link data
189
+ *
190
+ * This method analyzes router link properties and returns a comprehensive
191
+ * link resolution result including route information, navigation functions,
192
+ * HTML attributes, and event handlers. It's primarily used for:
193
+ * - Framework-agnostic link component implementation
194
+ * - Generating link attributes and navigation handlers
195
+ * - Computing active states and CSS classes
196
+ * - Creating event handlers for different frameworks
197
+ *
198
+ * @param props Router link configuration properties
199
+ * @returns Complete link resolution result with all necessary data
200
+ *
201
+ * @example
202
+ * ```typescript
203
+ * // Basic link resolution
204
+ * const linkData = router.resolveLink({
205
+ * to: '/user/123',
206
+ * type: 'push'
207
+ * });
208
+ *
209
+ * // Access resolved data
210
+ * console.log(linkData.route.path); // '/user/123'
211
+ * console.log(linkData.attributes.href); // Full href URL
212
+ * console.log(linkData.isActive); // Active state
213
+ *
214
+ * // Use navigation function
215
+ * linkData.navigate(); // Programmatic navigation
216
+ *
217
+ * // Get event handlers for React
218
+ * const handlers = linkData.createEventHandlers(name => `on${name.charAt(0).toUpperCase() + name.slice(1)}`);
219
+ * // handlers.onClick for React
220
+ * ```
295
221
  */
296
- checkLayerState(state) {
297
- const stateLayerConfigList = state[StateLayerConfigKey] || [];
298
- const layerConfigList = Object.keys(this.layerMap).map(Number);
299
- const stateLayerIdList = stateLayerConfigList.map(({ id }) => id).filter((id) => {
300
- return layerConfigList.includes(id);
222
+ resolveLink(props) {
223
+ return createLinkResolver(this, props);
224
+ }
225
+ async createLayer(toInput) {
226
+ var _a;
227
+ const layerOptions = isPlainObject(toInput) && toInput.layer || {};
228
+ const zIndex = (_a = layerOptions.zIndex) != null ? _a : this.parsedOptions.zIndex + LAYER_ID.next();
229
+ let promiseResolve;
230
+ let promise = new Promise((resolve) => {
231
+ promiseResolve = resolve;
301
232
  });
302
- if (stateLayerIdList.length === 0) {
303
- return false;
304
- }
305
- if (stateLayerIdList.length === 1 && stateLayerIdList[0] === this.layerId) {
306
- return false;
307
- }
308
- const createList = [];
309
- const destroyList = [];
310
- Object.entries(this.layerMap).forEach(([key, value]) => {
311
- if (stateLayerIdList.includes(Number(key))) {
312
- if (value.destroyed) {
313
- createList.push(Number(key));
233
+ const router = new Router({
234
+ rootStyle: {
235
+ position: "fixed",
236
+ top: "0",
237
+ left: "0",
238
+ width: "100%",
239
+ height: "100%",
240
+ zIndex: String(zIndex),
241
+ background: "rgba(0,0,0,.6)",
242
+ display: "flex",
243
+ alignItems: "center",
244
+ justifyContent: "center"
245
+ },
246
+ ...this.options,
247
+ context: this.parsedOptions.context,
248
+ mode: RouterMode.memory,
249
+ appId: void 0,
250
+ ...layerOptions.routerOptions,
251
+ handleBackBoundary(router2) {
252
+ router2.destroy();
253
+ promiseResolve({
254
+ type: "close",
255
+ route: router2.route
256
+ });
257
+ },
258
+ handleLayerClose(router2, data) {
259
+ router2.destroy();
260
+ if (isNotNullish(data)) {
261
+ promiseResolve({
262
+ type: "success",
263
+ route: router2.route,
264
+ data
265
+ });
266
+ } else {
267
+ promiseResolve({
268
+ type: "close",
269
+ route: router2.route
270
+ });
314
271
  }
315
- } else {
316
- destroyList.push(Number(key));
317
- }
272
+ },
273
+ layer: true
318
274
  });
319
- if (createList.length === 0 && destroyList.length === 0) {
320
- return false;
321
- }
322
- const activeId = Math.max(...stateLayerIdList);
323
- layerConfigList.forEach((id) => {
324
- const { router } = this.layerMap[id];
325
- if (activeId === id) {
326
- router.unfreeze();
275
+ const initRoute = await router.replace(toInput);
276
+ router.afterEach(async (to, from) => {
277
+ if (LAYER_SKIP_TYPES.has(to.type)) return;
278
+ let keepAlive = false;
279
+ if (layerOptions.keepAlive === "exact") {
280
+ keepAlive = to.path === initRoute.path;
281
+ } else if (layerOptions.keepAlive === "include") {
282
+ keepAlive = to.path.startsWith(initRoute.path);
283
+ } else if (typeof layerOptions.keepAlive === "function") {
284
+ keepAlive = await layerOptions.keepAlive(to, from, router);
327
285
  } else {
328
- router.freeze();
286
+ if (layerOptions.shouldClose) {
287
+ console.warn(
288
+ "[esmx-router] RouteLayerOptions.shouldClose is deprecated. Use keepAlive instead. Note: shouldClose returns true to close, keepAlive returns true to keep alive."
289
+ );
290
+ keepAlive = !await layerOptions.shouldClose(
291
+ to,
292
+ from,
293
+ router
294
+ );
295
+ } else {
296
+ keepAlive = to.path === initRoute.path;
297
+ }
329
298
  }
330
- });
331
- destroyList.forEach((id) => {
332
- const layer = this.layerMap[id];
333
- if (!layer.destroyed) {
334
- const { router, config } = layer;
335
- config.destroy();
299
+ if (!keepAlive) {
336
300
  router.destroy();
337
- router.freeze();
338
- layer.destroyed = true;
301
+ promiseResolve({
302
+ type: "push",
303
+ route: to
304
+ });
339
305
  }
340
306
  });
341
- createList.forEach((id) => {
342
- const layer = this.layerMap[id];
343
- if (layer.destroyed) {
344
- const { router, config } = layer;
345
- config.mount();
346
- router.unfreeze();
347
- layer.destroyed = false;
348
- }
349
- });
350
- this.layerConfigList = stateLayerConfigList;
351
- return true;
352
- }
353
- updateLayerState(route) {
354
- const layerConfig = this.layerConfigList.find((item) => {
355
- return item.id === this.layerId;
356
- });
357
- if (layerConfig) layerConfig.depth++;
358
- const stateConfigList = this.layerConfigList.filter(({ id }) => {
359
- var _a;
360
- return !((_a = this.layerMap[id]) == null ? void 0 : _a.destroyed);
361
- });
362
- const state = {
363
- ...history.state,
364
- [StateLayerConfigKey]: stateConfigList
307
+ if (layerOptions.push) {
308
+ router.navigation.pushHistoryState(
309
+ router.route.state,
310
+ router.route.url
311
+ );
312
+ promise = promise.then(async (result) => {
313
+ await this.navigation.backHistoryState();
314
+ return result;
315
+ });
316
+ }
317
+ if (layerOptions.autoPush) {
318
+ promise = promise.then(async (result) => {
319
+ if (result.type === "push") {
320
+ await this.push(result.route.url.href);
321
+ }
322
+ return result;
323
+ });
324
+ }
325
+ return {
326
+ promise,
327
+ router
365
328
  };
366
- window.history.replaceState(state, "", route.fullPath);
367
329
  }
368
- /**
369
- * 新开浏览器窗口的方法,在服务端会调用 push 作为替代
370
- */
371
- pushWindow(location2) {
372
- this.history.pushWindow(location2);
330
+ async pushLayer(toInput) {
331
+ const result = await this.transition.to(RouteType.pushLayer, toInput);
332
+ return result.handleResult;
373
333
  }
374
- /**
375
- * 替换当前浏览器窗口的方法,在服务端会调用 replace 作为替代
376
- */
377
- replaceWindow(location2) {
378
- this.history.replaceWindow(location2);
334
+ closeLayer(data) {
335
+ if (!this.isLayer) return;
336
+ this.parsedOptions.handleLayerClose(this, data);
379
337
  }
380
- /* 前往特定路由历史记录的方法,可以在历史记录前后移动 */
381
- go(delta = 0) {
382
- this.history.go(delta);
338
+ async renderToString(throwError = false) {
339
+ var _a, _b;
340
+ try {
341
+ const result = await ((_b = (_a = this.microApp.app) == null ? void 0 : _a.renderToString) == null ? void 0 : _b.call(_a));
342
+ const trimmed = result == null ? void 0 : result.trim();
343
+ const hasContent = trimmed && trimmed.length > 0;
344
+ if (hasContent && process.env.NODE_ENV !== "production") {
345
+ validateSsrRootElement(trimmed);
346
+ }
347
+ const ssrAttr = hasContent ? " data-ssr" : "";
348
+ return '<div id="'.concat(this.appId, '"').concat(ssrAttr, ">").concat(result != null ? result : "", "</div>");
349
+ } catch (e) {
350
+ if (throwError) throw e;
351
+ else console.error("[@esmx/router] SSR render failed:", e);
352
+ return null;
353
+ }
383
354
  }
384
- /* 路由历史记录前进方法 */
385
- forward() {
386
- this.history.forward();
355
+ beforeEach(guard) {
356
+ return this.transition.beforeEach(guard);
387
357
  }
388
- /* 路由历史记录后退方法 */
389
- back() {
390
- this.history.back();
358
+ afterEach(guard) {
359
+ return this.transition.afterEach(guard);
391
360
  }
392
- /* 根据获取当前所有活跃的路由Record对象 */
393
- getRoutes() {
394
- return this.matcher.getRoutes();
361
+ destroy() {
362
+ this.transition.destroy();
363
+ this.navigation.destroy();
364
+ this.microApp.destroy();
395
365
  }
396
366
  }
397
- export function createRouter(options) {
398
- return new Router(options);
399
- }