@esmx/router 3.0.0-rc.103

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 (52) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +77 -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 -0
  9. package/dist/index.mjs +13 -0
  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 +46 -0
  14. package/dist/micro-app.d.ts +18 -0
  15. package/dist/micro-app.mjs +85 -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 +94 -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 +53 -0
  23. package/dist/route-transition.mjs +356 -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 +139 -0
  28. package/dist/router.d.ts +122 -0
  29. package/dist/router.mjs +355 -0
  30. package/dist/scroll.d.ts +33 -0
  31. package/dist/scroll.mjs +49 -0
  32. package/dist/types.d.ts +282 -0
  33. package/dist/types.mjs +18 -0
  34. package/dist/util.d.ts +27 -0
  35. package/dist/util.mjs +67 -0
  36. package/package.json +62 -0
  37. package/src/error.ts +84 -0
  38. package/src/increment-id.ts +12 -0
  39. package/src/index.ts +67 -0
  40. package/src/location.ts +124 -0
  41. package/src/matcher.ts +68 -0
  42. package/src/micro-app.ts +101 -0
  43. package/src/navigation.ts +202 -0
  44. package/src/options.ts +135 -0
  45. package/src/route-task.ts +102 -0
  46. package/src/route-transition.ts +472 -0
  47. package/src/route.ts +335 -0
  48. package/src/router-link.ts +238 -0
  49. package/src/router.ts +395 -0
  50. package/src/scroll.ts +106 -0
  51. package/src/types.ts +381 -0
  52. package/src/util.ts +133 -0
@@ -0,0 +1,139 @@
1
+ const CSS_CLASSES = {
2
+ BASE: "router-link",
3
+ ACTIVE: "router-link-active",
4
+ EXACT_ACTIVE: "router-link-exact-active"
5
+ };
6
+ function normalizeNavigationType(props) {
7
+ if (props.replace) {
8
+ console.warn(
9
+ '[RouterLink] The `replace` property is deprecated and will be removed in a future version.\nPlease use `type="replace"` instead.\nBefore: <RouterLink replace={true} />\nAfter: <RouterLink type="replace" />'
10
+ );
11
+ return "replace";
12
+ }
13
+ return props.type || "push";
14
+ }
15
+ function getEventTypeList(eventType) {
16
+ const events = Array.isArray(eventType) ? eventType : [eventType];
17
+ const validEvents = events.filter((type) => typeof type === "string").map((type) => type.trim()).filter(Boolean);
18
+ return validEvents.length ? validEvents : ["click"];
19
+ }
20
+ function shouldHandleNavigation(e) {
21
+ var _a;
22
+ if (e.defaultPrevented) return false;
23
+ if (e instanceof MouseEvent) {
24
+ if (e.metaKey || e.altKey || e.ctrlKey || e.shiftKey) return false;
25
+ if (e.button !== void 0 && e.button !== 0) return false;
26
+ }
27
+ (_a = e.preventDefault) == null ? void 0 : _a.call(e);
28
+ return true;
29
+ }
30
+ async function executeNavigation(router, props, linkType) {
31
+ const { to, layerOptions } = props;
32
+ switch (linkType) {
33
+ case "push":
34
+ await router.push(to);
35
+ break;
36
+ case "replace":
37
+ await router.replace(to);
38
+ break;
39
+ case "pushWindow":
40
+ await router.pushWindow(to);
41
+ break;
42
+ case "replaceWindow":
43
+ await router.replaceWindow(to);
44
+ break;
45
+ case "pushLayer":
46
+ await router.pushLayer(
47
+ layerOptions ? typeof to === "string" ? { path: to, layer: layerOptions } : { ...to, layer: layerOptions } : to
48
+ );
49
+ break;
50
+ default:
51
+ await router.push(to);
52
+ }
53
+ }
54
+ function createNavigateFunction(router, props, navigationType) {
55
+ return async (e) => {
56
+ if (shouldHandleNavigation(e)) {
57
+ await executeNavigation(router, props, navigationType);
58
+ }
59
+ };
60
+ }
61
+ function computeAttributes(href, navigationType, isExternal, isActive, isExactActive, activeClass) {
62
+ const isNewWindow = navigationType === "pushWindow";
63
+ const classes = [CSS_CLASSES.BASE];
64
+ if (isActive) {
65
+ classes.push(activeClass || CSS_CLASSES.ACTIVE);
66
+ }
67
+ if (isExactActive) {
68
+ classes.push(CSS_CLASSES.EXACT_ACTIVE);
69
+ }
70
+ const attributes = {
71
+ href,
72
+ class: classes.join(" ")
73
+ };
74
+ if (isNewWindow) {
75
+ attributes.target = "_blank";
76
+ }
77
+ const relParts = [];
78
+ if (isNewWindow) {
79
+ relParts.push("noopener", "noreferrer");
80
+ }
81
+ if (isExternal) {
82
+ relParts.push("external", "nofollow");
83
+ }
84
+ if (relParts.length > 0) {
85
+ attributes.rel = relParts.join(" ");
86
+ }
87
+ return attributes;
88
+ }
89
+ function createEventHandlersGenerator(router, props, navigationType, eventTypes) {
90
+ return (format) => {
91
+ const handlers = {};
92
+ const navigate = createNavigateFunction(router, props, navigationType);
93
+ eventTypes.forEach((eventType) => {
94
+ var _a;
95
+ const eventName = (_a = format == null ? void 0 : format(eventType)) != null ? _a : eventType.toLowerCase();
96
+ handlers[eventName] = (event) => {
97
+ var _a2;
98
+ (_a2 = props.beforeNavigate) == null ? void 0 : _a2.call(props, event, eventType);
99
+ return navigate(event);
100
+ };
101
+ });
102
+ return handlers;
103
+ };
104
+ }
105
+ export function createLinkResolver(router, props) {
106
+ const route = router.resolve(props.to);
107
+ const type = normalizeNavigationType(props);
108
+ const href = route.url.href;
109
+ const isActive = router.isRouteMatched(route, props.exact);
110
+ const isExactActive = router.isRouteMatched(route, "exact");
111
+ const isExternal = route.url.origin !== router.route.url.origin;
112
+ const attributes = computeAttributes(
113
+ href,
114
+ type,
115
+ isExternal,
116
+ isActive,
117
+ isExactActive,
118
+ props.activeClass
119
+ );
120
+ const eventTypes = getEventTypeList(props.event || "click");
121
+ const createEventHandlers = createEventHandlersGenerator(
122
+ router,
123
+ props,
124
+ type,
125
+ eventTypes
126
+ );
127
+ const navigate = createNavigateFunction(router, props, type);
128
+ return {
129
+ route,
130
+ type,
131
+ isActive,
132
+ isExactActive,
133
+ isExternal,
134
+ tag: props.tag || "a",
135
+ attributes,
136
+ navigate,
137
+ createEventHandlers
138
+ };
139
+ }
@@ -0,0 +1,122 @@
1
+ import { MicroApp } from './micro-app';
2
+ import { Navigation } from './navigation';
3
+ import { Route } from './route';
4
+ import { RouteTransition } from './route-transition';
5
+ import type { RouteConfirmHook, RouteLayerResult, RouteLocationInput, RouteMatchType, RouteNotifyHook, RouterLinkProps, RouterLinkResolved, RouterOptions, RouterParsedOptions } from './types';
6
+ import { RouterMode, RouteType } from './types';
7
+ export declare class Router {
8
+ readonly options: RouterOptions;
9
+ readonly parsedOptions: RouterParsedOptions;
10
+ readonly isLayer: boolean;
11
+ readonly navigation: Navigation;
12
+ readonly microApp: MicroApp;
13
+ readonly transition: RouteTransition;
14
+ get route(): Route;
15
+ get context(): Record<string | symbol, unknown>;
16
+ get data(): Record<string | symbol, unknown>;
17
+ get root(): string | HTMLElement;
18
+ get mode(): RouterMode;
19
+ get base(): URL;
20
+ get req(): import("http").IncomingMessage | null;
21
+ get res(): import("http").ServerResponse<import("http").IncomingMessage> | null;
22
+ constructor(options: RouterOptions);
23
+ push(toInput: RouteLocationInput): Promise<Route>;
24
+ replace(toInput: RouteLocationInput): Promise<Route>;
25
+ pushWindow(toInput: RouteLocationInput): Promise<Route>;
26
+ replaceWindow(toInput: RouteLocationInput): Promise<Route>;
27
+ restartApp(toInput?: RouteLocationInput): Promise<Route>;
28
+ back(): Promise<Route | null>;
29
+ go(index: number): Promise<Route | null>;
30
+ forward(): Promise<Route | null>;
31
+ /**
32
+ * Parse route location without performing actual navigation
33
+ *
34
+ * This method is used to parse route configuration and return the corresponding route object,
35
+ * but does not trigger actual page navigation. It is mainly used for the following scenarios:
36
+ * - Generate link URLs without jumping
37
+ * - Pre-check route matching
38
+ * - Get route parameters, meta information, etc.
39
+ * - Test the validity of route configuration
40
+ *
41
+ * @param toInput Target route location, can be a string path or route configuration object
42
+ * @returns Parsed route object containing complete route information
43
+ *
44
+ * @example
45
+ * ```typescript
46
+ * // Parse string path
47
+ * const route = router.resolve('/user/123');
48
+ * const url = route.url.href; // Get complete URL
49
+ *
50
+ * // Parse named route
51
+ * const userRoute = router.resolve({
52
+ * name: 'user',
53
+ * params: { id: '123' }
54
+ * });
55
+ * console.log(userRoute.params.id); // '123'
56
+ *
57
+ * // Check route validity
58
+ * const testRoute = router.resolve('/some/path');
59
+ * if (testRoute.matched.length > 0) {
60
+ * // Route matched successfully
61
+ * }
62
+ * ```
63
+ */
64
+ resolve(toInput: RouteLocationInput, toType?: RouteType): Route;
65
+ /**
66
+ * Check if the route matches the current route
67
+ *
68
+ * @param toRoute Target route object to compare
69
+ * @param matchType Match type
70
+ * - 'route': Route-level matching, compare if route configurations are the same
71
+ * - 'exact': Exact matching, compare if paths are completely the same
72
+ * - 'include': Include matching, check if current path contains target path
73
+ * @returns Whether it matches
74
+ */
75
+ isRouteMatched(toRoute: Route, matchType?: RouteMatchType): boolean;
76
+ /**
77
+ * Resolve router link configuration and return complete link data
78
+ *
79
+ * This method analyzes router link properties and returns a comprehensive
80
+ * link resolution result including route information, navigation functions,
81
+ * HTML attributes, and event handlers. It's primarily used for:
82
+ * - Framework-agnostic link component implementation
83
+ * - Generating link attributes and navigation handlers
84
+ * - Computing active states and CSS classes
85
+ * - Creating event handlers for different frameworks
86
+ *
87
+ * @param props Router link configuration properties
88
+ * @returns Complete link resolution result with all necessary data
89
+ *
90
+ * @example
91
+ * ```typescript
92
+ * // Basic link resolution
93
+ * const linkData = router.resolveLink({
94
+ * to: '/user/123',
95
+ * type: 'push'
96
+ * });
97
+ *
98
+ * // Access resolved data
99
+ * console.log(linkData.route.path); // '/user/123'
100
+ * console.log(linkData.attributes.href); // Full href URL
101
+ * console.log(linkData.isActive); // Active state
102
+ *
103
+ * // Use navigation function
104
+ * linkData.navigate(); // Programmatic navigation
105
+ *
106
+ * // Get event handlers for React
107
+ * const handlers = linkData.createEventHandlers(name => `on${name.charAt(0).toUpperCase() + name.slice(1)}`);
108
+ * // handlers.onClick for React
109
+ * ```
110
+ */
111
+ resolveLink(props: RouterLinkProps): RouterLinkResolved;
112
+ createLayer(toInput: RouteLocationInput): Promise<{
113
+ promise: Promise<RouteLayerResult>;
114
+ router: Router;
115
+ }>;
116
+ pushLayer(toInput: RouteLocationInput): Promise<RouteLayerResult>;
117
+ closeLayer(data?: any): void;
118
+ renderToString(throwError?: boolean): Promise<string | null>;
119
+ beforeEach(guard: RouteConfirmHook): () => void;
120
+ afterEach(guard: RouteNotifyHook): () => void;
121
+ destroy(): void;
122
+ }
@@ -0,0 +1,355 @@
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";
12
+ import { isNotNullish, isPlainObject, isRouteMatched } from "./util.mjs";
13
+ export class Router {
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
+ }
35
+ get route() {
36
+ const route = this.transition.route;
37
+ if (route === null) {
38
+ throw new Error(
39
+ "No active route found. Please navigate to a route first using router.push() or router.replace()."
40
+ );
41
+ }
42
+ return route;
43
+ }
44
+ get context() {
45
+ return this.parsedOptions.context;
46
+ }
47
+ get data() {
48
+ return this.parsedOptions.data;
49
+ }
50
+ get root() {
51
+ return this.parsedOptions.root;
52
+ }
53
+ get mode() {
54
+ return this.parsedOptions.mode;
55
+ }
56
+ get base() {
57
+ return this.parsedOptions.base;
58
+ }
59
+ get req() {
60
+ var _a;
61
+ return (_a = this.parsedOptions.req) != null ? _a : null;
62
+ }
63
+ get res() {
64
+ var _a;
65
+ return (_a = this.parsedOptions.res) != null ? _a : null;
66
+ }
67
+ push(toInput) {
68
+ return this.transition.to(RouteType.push, toInput);
69
+ }
70
+ replace(toInput) {
71
+ return this.transition.to(RouteType.replace, toInput);
72
+ }
73
+ pushWindow(toInput) {
74
+ return this.transition.to(RouteType.pushWindow, toInput);
75
+ }
76
+ replaceWindow(toInput) {
77
+ return this.transition.to(RouteType.replaceWindow, toInput);
78
+ }
79
+ restartApp(toInput) {
80
+ return this.transition.to(
81
+ RouteType.restartApp,
82
+ toInput != null ? toInput : this.route.url.href
83
+ );
84
+ }
85
+ async back() {
86
+ const result = await this.navigation.go(-1);
87
+ if (result === null) {
88
+ this.parsedOptions.handleBackBoundary(this);
89
+ return null;
90
+ }
91
+ return this.transition.to(RouteType.back, {
92
+ url: result.url,
93
+ state: result.state
94
+ });
95
+ }
96
+ async go(index) {
97
+ if (index === 0) return null;
98
+ const result = await this.navigation.go(index);
99
+ if (result === null) {
100
+ if (index < 0) {
101
+ this.parsedOptions.handleBackBoundary(this);
102
+ }
103
+ return null;
104
+ }
105
+ return this.transition.to(RouteType.go, {
106
+ url: result.url,
107
+ state: result.state
108
+ });
109
+ }
110
+ async forward() {
111
+ const result = await this.navigation.go(1);
112
+ if (result === null) return null;
113
+ return this.transition.to(RouteType.forward, {
114
+ url: result.url,
115
+ state: result.state
116
+ });
117
+ }
118
+ /**
119
+ * Parse route location without performing actual navigation
120
+ *
121
+ * This method is used to parse route configuration and return the corresponding route object,
122
+ * but does not trigger actual page navigation. It is mainly used for the following scenarios:
123
+ * - Generate link URLs without jumping
124
+ * - Pre-check route matching
125
+ * - Get route parameters, meta information, etc.
126
+ * - Test the validity of route configuration
127
+ *
128
+ * @param toInput Target route location, can be a string path or route configuration object
129
+ * @returns Parsed route object containing complete route information
130
+ *
131
+ * @example
132
+ * ```typescript
133
+ * // Parse string path
134
+ * const route = router.resolve('/user/123');
135
+ * const url = route.url.href; // Get complete URL
136
+ *
137
+ * // Parse named route
138
+ * const userRoute = router.resolve({
139
+ * name: 'user',
140
+ * params: { id: '123' }
141
+ * });
142
+ * console.log(userRoute.params.id); // '123'
143
+ *
144
+ * // Check route validity
145
+ * const testRoute = router.resolve('/some/path');
146
+ * if (testRoute.matched.length > 0) {
147
+ * // Route matched successfully
148
+ * }
149
+ * ```
150
+ */
151
+ resolve(toInput, toType) {
152
+ var _a, _b;
153
+ return new Route({
154
+ options: this.parsedOptions,
155
+ toType,
156
+ toInput,
157
+ from: (_b = (_a = this.transition.route) == null ? void 0 : _a.url) != null ? _b : null
158
+ });
159
+ }
160
+ /**
161
+ * Check if the route matches the current route
162
+ *
163
+ * @param toRoute Target route object to compare
164
+ * @param matchType Match type
165
+ * - 'route': Route-level matching, compare if route configurations are the same
166
+ * - 'exact': Exact matching, compare if paths are completely the same
167
+ * - 'include': Include matching, check if current path contains target path
168
+ * @returns Whether it matches
169
+ */
170
+ isRouteMatched(toRoute, matchType = "include") {
171
+ const currentRoute = this.transition.route;
172
+ if (!currentRoute) return false;
173
+ return isRouteMatched(currentRoute, toRoute, matchType);
174
+ }
175
+ /**
176
+ * Resolve router link configuration and return complete link data
177
+ *
178
+ * This method analyzes router link properties and returns a comprehensive
179
+ * link resolution result including route information, navigation functions,
180
+ * HTML attributes, and event handlers. It's primarily used for:
181
+ * - Framework-agnostic link component implementation
182
+ * - Generating link attributes and navigation handlers
183
+ * - Computing active states and CSS classes
184
+ * - Creating event handlers for different frameworks
185
+ *
186
+ * @param props Router link configuration properties
187
+ * @returns Complete link resolution result with all necessary data
188
+ *
189
+ * @example
190
+ * ```typescript
191
+ * // Basic link resolution
192
+ * const linkData = router.resolveLink({
193
+ * to: '/user/123',
194
+ * type: 'push'
195
+ * });
196
+ *
197
+ * // Access resolved data
198
+ * console.log(linkData.route.path); // '/user/123'
199
+ * console.log(linkData.attributes.href); // Full href URL
200
+ * console.log(linkData.isActive); // Active state
201
+ *
202
+ * // Use navigation function
203
+ * linkData.navigate(); // Programmatic navigation
204
+ *
205
+ * // Get event handlers for React
206
+ * const handlers = linkData.createEventHandlers(name => `on${name.charAt(0).toUpperCase() + name.slice(1)}`);
207
+ * // handlers.onClick for React
208
+ * ```
209
+ */
210
+ resolveLink(props) {
211
+ return createLinkResolver(this, props);
212
+ }
213
+ async createLayer(toInput) {
214
+ var _a;
215
+ const layerOptions = isPlainObject(toInput) && toInput.layer || {};
216
+ const zIndex = (_a = layerOptions.zIndex) != null ? _a : this.parsedOptions.zIndex + LAYER_ID.next();
217
+ let promiseResolve;
218
+ let promise = new Promise((resolve) => {
219
+ promiseResolve = resolve;
220
+ });
221
+ const router = new Router({
222
+ rootStyle: {
223
+ position: "fixed",
224
+ top: "0",
225
+ left: "0",
226
+ width: "100%",
227
+ height: "100%",
228
+ zIndex: String(zIndex),
229
+ background: "rgba(0,0,0,.6)",
230
+ display: "flex",
231
+ alignItems: "center",
232
+ justifyContent: "center"
233
+ },
234
+ ...this.options,
235
+ context: this.parsedOptions.context,
236
+ mode: RouterMode.memory,
237
+ root: void 0,
238
+ ...layerOptions.routerOptions,
239
+ handleBackBoundary(router2) {
240
+ router2.destroy();
241
+ promiseResolve({
242
+ type: "close",
243
+ route: router2.route
244
+ });
245
+ },
246
+ handleLayerClose(router2, data) {
247
+ router2.destroy();
248
+ if (isNotNullish(data)) {
249
+ promiseResolve({
250
+ type: "success",
251
+ route: router2.route,
252
+ data
253
+ });
254
+ } else {
255
+ promiseResolve({
256
+ type: "close",
257
+ route: router2.route
258
+ });
259
+ }
260
+ },
261
+ layer: true
262
+ });
263
+ const initRoute = await router.replace(toInput);
264
+ router.afterEach(async (to, from) => {
265
+ if (![
266
+ RouteType.pushWindow,
267
+ RouteType.replaceWindow,
268
+ RouteType.replace,
269
+ RouteType.restartApp,
270
+ RouteType.pushLayer
271
+ ].includes(to.type))
272
+ return;
273
+ let keepAlive = false;
274
+ if (layerOptions.keepAlive === "exact") {
275
+ keepAlive = to.path === initRoute.path;
276
+ } else if (layerOptions.keepAlive === "include") {
277
+ keepAlive = to.path.startsWith(initRoute.path);
278
+ } else if (typeof layerOptions.keepAlive === "function") {
279
+ keepAlive = await layerOptions.keepAlive(to, from, router);
280
+ } else {
281
+ if (layerOptions.shouldClose) {
282
+ console.warn(
283
+ "[esmx-router] RouteLayerOptions.shouldClose is deprecated. Use keepAlive instead. Note: shouldClose returns true to close, keepAlive returns true to keep alive."
284
+ );
285
+ keepAlive = !await layerOptions.shouldClose(
286
+ to,
287
+ from,
288
+ router
289
+ );
290
+ } else {
291
+ keepAlive = to.path === initRoute.path;
292
+ }
293
+ }
294
+ if (!keepAlive) {
295
+ router.destroy();
296
+ promiseResolve({
297
+ type: "push",
298
+ route: to
299
+ });
300
+ }
301
+ });
302
+ if (layerOptions.push) {
303
+ router.navigation.pushHistoryState(
304
+ router.route.state,
305
+ router.route.url
306
+ );
307
+ promise = promise.then(async (result) => {
308
+ await this.navigation.backHistoryState();
309
+ return result;
310
+ });
311
+ }
312
+ if (layerOptions.autoPush) {
313
+ promise = promise.then(async (result) => {
314
+ if (result.type === "push") {
315
+ await this.push(result.route.url.href);
316
+ }
317
+ return result;
318
+ });
319
+ }
320
+ return {
321
+ promise,
322
+ router
323
+ };
324
+ }
325
+ async pushLayer(toInput) {
326
+ const result = await this.transition.to(RouteType.pushLayer, toInput);
327
+ return result.handleResult;
328
+ }
329
+ closeLayer(data) {
330
+ if (!this.isLayer) return;
331
+ this.parsedOptions.handleLayerClose(this, data);
332
+ }
333
+ async renderToString(throwError = false) {
334
+ var _a, _b;
335
+ try {
336
+ const result = await ((_b = (_a = this.microApp.app) == null ? void 0 : _a.renderToString) == null ? void 0 : _b.call(_a));
337
+ return result != null ? result : null;
338
+ } catch (e) {
339
+ if (throwError) throw e;
340
+ else console.error(e);
341
+ return null;
342
+ }
343
+ }
344
+ beforeEach(guard) {
345
+ return this.transition.beforeEach(guard);
346
+ }
347
+ afterEach(guard) {
348
+ return this.transition.afterEach(guard);
349
+ }
350
+ destroy() {
351
+ this.transition.destroy();
352
+ this.navigation.destroy();
353
+ this.microApp.destroy();
354
+ }
355
+ }
@@ -0,0 +1,33 @@
1
+ /** Internal {@link ScrollToOptions | `ScrollToOptions`}: `left` and `top` properties always have values */
2
+ interface _ScrollPosition extends ScrollToOptions {
3
+ left: number;
4
+ top: number;
5
+ }
6
+ export interface ScrollPositionElement extends ScrollToOptions {
7
+ /**
8
+ * A valid CSS selector. Some special characters need to be escaped (https://mathiasbynens.be/notes/css-escapes).
9
+ * @example
10
+ * Here are some examples:
11
+ *
12
+ * - `.title`
13
+ * - `.content:first-child`
14
+ * - `#marker`
15
+ * - `#marker\~with\~symbols`
16
+ * - `#marker.with.dot`: Selects `class="with dot" id="marker"`, not `id="marker.with.dot"`
17
+ *
18
+ */
19
+ el: string | Element;
20
+ }
21
+ /** Scroll parameters */
22
+ export type ScrollPosition = ScrollToOptions | ScrollPositionElement;
23
+ /** Get current window scroll position */
24
+ export declare const winScrollPos: () => _ScrollPosition;
25
+ /** Scroll to specified position */
26
+ export declare function scrollToPosition(position: ScrollPosition): void;
27
+ /** Stored scroll positions */
28
+ export declare const scrollPositions: Map<string, _ScrollPosition>;
29
+ /** Save scroll position */
30
+ export declare function saveScrollPosition(key: string, scrollPosition?: _ScrollPosition): void;
31
+ /** Get saved scroll position */
32
+ export declare function getSavedScrollPosition(key: string, defaultValue?: _ScrollPosition | null): _ScrollPosition | null;
33
+ export {};
@@ -0,0 +1,49 @@
1
+ export const winScrollPos = () => ({
2
+ left: window.scrollX,
3
+ top: window.scrollY
4
+ });
5
+ function getElementPosition(el, offset) {
6
+ const docRect = document.documentElement.getBoundingClientRect();
7
+ const elRect = el.getBoundingClientRect();
8
+ return {
9
+ behavior: offset.behavior,
10
+ left: elRect.left - docRect.left - (offset.left || 0),
11
+ top: elRect.top - docRect.top - (offset.top || 0)
12
+ };
13
+ }
14
+ export function scrollToPosition(position) {
15
+ if ("el" in position) {
16
+ const positionEl = position.el;
17
+ const el = typeof positionEl === "string" ? document.querySelector(positionEl) : positionEl;
18
+ if (!el) return;
19
+ position = getElementPosition(el, position);
20
+ }
21
+ if ("scrollBehavior" in document.documentElement.style) {
22
+ window.scrollTo(position);
23
+ } else {
24
+ window.scrollTo(
25
+ Number.isFinite(position.left) ? position.left : window.scrollX,
26
+ Number.isFinite(position.top) ? position.top : window.scrollY
27
+ );
28
+ }
29
+ }
30
+ export const scrollPositions = /* @__PURE__ */ new Map();
31
+ const POSITION_KEY = "__scroll_position_key";
32
+ export function saveScrollPosition(key, scrollPosition = winScrollPos()) {
33
+ scrollPosition = { ...scrollPosition };
34
+ scrollPositions.set(key, scrollPosition);
35
+ try {
36
+ if (location.href !== key) return;
37
+ const stateCopy = {
38
+ ...history.state || {},
39
+ [POSITION_KEY]: scrollPosition
40
+ };
41
+ history.replaceState(stateCopy, "");
42
+ } catch (error) {
43
+ }
44
+ }
45
+ export function getSavedScrollPosition(key, defaultValue = null) {
46
+ const scroll = scrollPositions.get(key) || history.state[POSITION_KEY];
47
+ scrollPositions.delete(key);
48
+ return scroll || defaultValue;
49
+ }