mobx-route 0.19.0 → 0.20.1
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.
- package/README.md +2 -2
- package/index.cjs +93 -57
- package/index.cjs.map +1 -1
- package/index.d.ts +18 -13
- package/index.js +94 -58
- package/index.js.map +1 -1
- package/package.json +1 -1
- package/react.cjs +20 -11
- package/react.cjs.map +1 -1
- package/react.js +20 -11
- package/react.js.map +1 -1
package/README.md
CHANGED
|
@@ -22,9 +22,9 @@ _Uses [`path-to-regexp` power](https://www.npmjs.com/package/path-to-regexp)_
|
|
|
22
22
|
|
|
23
23
|
|
|
24
24
|
```ts
|
|
25
|
-
import {
|
|
25
|
+
import { createRoute } from "mobx-route";
|
|
26
26
|
|
|
27
|
-
const userDetails =
|
|
27
|
+
const userDetails = createRoute("/users/:id");
|
|
28
28
|
|
|
29
29
|
await userDetails.open({ id: 1 }); // path params are required
|
|
30
30
|
|
package/index.cjs
CHANGED
|
@@ -34,7 +34,8 @@ const routeConfig = complex.createGlobalDynamicConfig(
|
|
|
34
34
|
location,
|
|
35
35
|
queryParams
|
|
36
36
|
};
|
|
37
|
-
}
|
|
37
|
+
},
|
|
38
|
+
Symbol.for("MOBX_ROUTE_CONFIG")
|
|
38
39
|
);
|
|
39
40
|
class Route {
|
|
40
41
|
constructor(path, config = {}) {
|
|
@@ -46,35 +47,28 @@ class Route {
|
|
|
46
47
|
this.isIndex = !!this.config.index;
|
|
47
48
|
this.isHash = !!this.config.hash;
|
|
48
49
|
this.meta = this.config.meta;
|
|
50
|
+
this.status = "unknown";
|
|
49
51
|
this.parent = config.parent ?? null;
|
|
50
|
-
mobx.computed
|
|
52
|
+
mobx.computed(this, "isPathMatched");
|
|
53
|
+
mobx.computed(this, "isOpened");
|
|
51
54
|
mobx.computed.struct(this, "data");
|
|
52
55
|
mobx.computed.struct(this, "params");
|
|
53
|
-
mobx.computed
|
|
54
|
-
mobx.computed
|
|
55
|
-
mobx.computed
|
|
56
|
+
mobx.computed(this, "currentPath");
|
|
57
|
+
mobx.computed(this, "hasOpenedChildren");
|
|
58
|
+
mobx.computed(this, "isAbleToMergeQuery");
|
|
56
59
|
mobx.computed(this, "baseUrl");
|
|
57
60
|
mobx.observable(this, "children");
|
|
58
61
|
mobx.observable.ref(this, "parent");
|
|
62
|
+
mobx.observable.ref(this, "status");
|
|
63
|
+
mobx.computed(this, "isOpening");
|
|
59
64
|
mobx.action(this, "addChildren");
|
|
65
|
+
mobx.action(this, "confirmOpening");
|
|
66
|
+
mobx.action(this, "confirmClosing");
|
|
60
67
|
mobx.action(this, "removeChildren");
|
|
61
68
|
mobx.makeObservable(this);
|
|
62
|
-
mobx.
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
}
|
|
66
|
-
this.reactionDisposer = mobx.reaction(
|
|
67
|
-
() => this.isOpened,
|
|
68
|
-
this.processOpenedState,
|
|
69
|
-
{
|
|
70
|
-
signal: this.abortController.signal,
|
|
71
|
-
fireImmediately: true
|
|
72
|
-
}
|
|
73
|
-
);
|
|
74
|
-
});
|
|
75
|
-
mobx.onBecomeUnobserved(this, "isOpened", () => {
|
|
76
|
-
this.reactionDisposer?.();
|
|
77
|
-
this.reactionDisposer = void 0;
|
|
69
|
+
mobx.reaction(() => this.isPathMatched, this.checkPathMatch, {
|
|
70
|
+
signal: this.abortController.signal,
|
|
71
|
+
fireImmediately: true
|
|
78
72
|
});
|
|
79
73
|
}
|
|
80
74
|
abortController;
|
|
@@ -84,7 +78,8 @@ class Route {
|
|
|
84
78
|
_tokenData;
|
|
85
79
|
_matcher;
|
|
86
80
|
_compiler;
|
|
87
|
-
|
|
81
|
+
skipPathMatchCheck = false;
|
|
82
|
+
status;
|
|
88
83
|
meta;
|
|
89
84
|
/**
|
|
90
85
|
* Indicates if this route is an index route. Index routes activate when parent route path matches exactly.
|
|
@@ -120,7 +115,7 @@ class Route {
|
|
|
120
115
|
return { params: {}, path: pathnameToCheck };
|
|
121
116
|
}
|
|
122
117
|
this._matcher ??= pathToRegexp.match(this.tokenData, {
|
|
123
|
-
end: false,
|
|
118
|
+
end: this.config.exact ?? false,
|
|
124
119
|
...this.config.matchOptions
|
|
125
120
|
});
|
|
126
121
|
const parsed = this._matcher(pathnameToCheck);
|
|
@@ -129,6 +124,9 @@ class Route {
|
|
|
129
124
|
}
|
|
130
125
|
return parsed;
|
|
131
126
|
}
|
|
127
|
+
get isOpening() {
|
|
128
|
+
return this.status === "opening";
|
|
129
|
+
}
|
|
132
130
|
/**
|
|
133
131
|
* Matched path segment for current URL.
|
|
134
132
|
*
|
|
@@ -160,13 +158,16 @@ class Route {
|
|
|
160
158
|
}
|
|
161
159
|
return params;
|
|
162
160
|
}
|
|
161
|
+
get isPathMatched() {
|
|
162
|
+
return this.parsedPathData !== null;
|
|
163
|
+
}
|
|
163
164
|
/**
|
|
164
165
|
* Defines the "open" state for this route.
|
|
165
166
|
*
|
|
166
167
|
* [**Documentation**](https://js2me.github.io/mobx-route/core/Route.html#isopened-boolean)
|
|
167
168
|
*/
|
|
168
169
|
get isOpened() {
|
|
169
|
-
if (this.params === null || this.
|
|
170
|
+
if (!this.isPathMatched || this.params === null || this.status !== "open-confirmed") {
|
|
170
171
|
return false;
|
|
171
172
|
}
|
|
172
173
|
return !this.config.checkOpened || this.config.checkOpened(this.parsedPathData);
|
|
@@ -223,9 +224,7 @@ class Route {
|
|
|
223
224
|
};
|
|
224
225
|
const urlCreateParams = this.config.createUrl?.(defaultUrlCreateParams, this.query.data) ?? routeConfig.get().createUrl?.(defaultUrlCreateParams, this.query.data) ?? defaultUrlCreateParams;
|
|
225
226
|
const path = this._compiler(this.processParams(urlCreateParams.params));
|
|
226
|
-
const url =
|
|
227
|
-
""
|
|
228
|
-
);
|
|
227
|
+
const url = `${urlCreateParams.baseUrl || ""}${this.isHash ? "#" : ""}${path}`;
|
|
229
228
|
if (outputParams?.omitQuery) {
|
|
230
229
|
return url;
|
|
231
230
|
}
|
|
@@ -254,59 +253,96 @@ class Route {
|
|
|
254
253
|
url = this.createUrl(args[0], query);
|
|
255
254
|
}
|
|
256
255
|
const state = rawState ?? null;
|
|
257
|
-
const
|
|
256
|
+
const trx = {
|
|
258
257
|
url,
|
|
259
258
|
params,
|
|
260
259
|
replace,
|
|
261
260
|
state,
|
|
262
261
|
query
|
|
263
262
|
};
|
|
264
|
-
const
|
|
265
|
-
if (
|
|
263
|
+
const isConfirmed = await this.confirmOpening(trx);
|
|
264
|
+
if (!isConfirmed) {
|
|
266
265
|
return;
|
|
267
266
|
}
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
if (replace) {
|
|
272
|
-
this.history.replace(url, state);
|
|
267
|
+
this.skipPathMatchCheck = true;
|
|
268
|
+
if (trx.replace) {
|
|
269
|
+
this.history.replace(trx.url, trx.state);
|
|
273
270
|
} else {
|
|
274
|
-
this.history.push(url, state);
|
|
271
|
+
this.history.push(trx.url, trx.state);
|
|
275
272
|
}
|
|
276
|
-
|
|
277
|
-
|
|
273
|
+
}
|
|
274
|
+
get tokenData() {
|
|
275
|
+
if (!this._tokenData) {
|
|
276
|
+
this._tokenData = pathToRegexp.parse(this.path, this.config.parseOptions);
|
|
278
277
|
}
|
|
278
|
+
return this._tokenData;
|
|
279
279
|
}
|
|
280
|
-
|
|
280
|
+
async confirmOpening(trx) {
|
|
281
|
+
this.status = "opening";
|
|
281
282
|
if (this.config.beforeOpen) {
|
|
282
|
-
|
|
283
|
+
const feedback = await this.config.beforeOpen(trx);
|
|
284
|
+
if (feedback === false) {
|
|
285
|
+
mobx.runInAction(() => {
|
|
286
|
+
this.status = "open-rejected";
|
|
287
|
+
});
|
|
288
|
+
return false;
|
|
289
|
+
}
|
|
290
|
+
if (typeof feedback === "object") {
|
|
291
|
+
mobx.runInAction(() => {
|
|
292
|
+
this.status = "open-confirmed";
|
|
293
|
+
});
|
|
294
|
+
return Object.assign(trx, feedback);
|
|
295
|
+
}
|
|
283
296
|
}
|
|
297
|
+
mobx.runInAction(() => {
|
|
298
|
+
this.status = "open-confirmed";
|
|
299
|
+
});
|
|
284
300
|
return true;
|
|
285
301
|
}
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
return this.config.afterClose();
|
|
289
|
-
}
|
|
302
|
+
confirmClosing() {
|
|
303
|
+
this.status = "closed";
|
|
290
304
|
return true;
|
|
291
305
|
}
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
}
|
|
298
|
-
firstOpenedStateCheck = true;
|
|
299
|
-
processOpenedState = (isOpened) => {
|
|
300
|
-
if (this.firstOpenedStateCheck) {
|
|
301
|
-
this.firstOpenedStateCheck = false;
|
|
302
|
-
if (!isOpened) {
|
|
306
|
+
firstPathMatchingRun = true;
|
|
307
|
+
checkPathMatch = async (isPathMathched) => {
|
|
308
|
+
if (this.firstPathMatchingRun) {
|
|
309
|
+
this.firstPathMatchingRun = false;
|
|
310
|
+
if (!isPathMathched) {
|
|
303
311
|
return;
|
|
304
312
|
}
|
|
305
313
|
}
|
|
306
|
-
if (
|
|
314
|
+
if (this.skipPathMatchCheck) {
|
|
315
|
+
this.skipPathMatchCheck = false;
|
|
316
|
+
return;
|
|
317
|
+
}
|
|
318
|
+
if (isPathMathched) {
|
|
319
|
+
const trx = {
|
|
320
|
+
url: this.parsedPathData.path,
|
|
321
|
+
params: this.parsedPathData.params,
|
|
322
|
+
state: this.history.location.state,
|
|
323
|
+
query: this.query.data
|
|
324
|
+
};
|
|
325
|
+
const nextTrxOrConfirmed = await this.confirmOpening(trx);
|
|
326
|
+
if (!nextTrxOrConfirmed) {
|
|
327
|
+
return;
|
|
328
|
+
}
|
|
307
329
|
this.config.afterOpen?.(this.parsedPathData, this);
|
|
330
|
+
if (typeof nextTrxOrConfirmed === "object") {
|
|
331
|
+
if (nextTrxOrConfirmed.replace) {
|
|
332
|
+
this.history.replace(
|
|
333
|
+
nextTrxOrConfirmed.url,
|
|
334
|
+
nextTrxOrConfirmed.state
|
|
335
|
+
);
|
|
336
|
+
} else {
|
|
337
|
+
this.history.push(nextTrxOrConfirmed.url, nextTrxOrConfirmed.state);
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
return;
|
|
308
341
|
} else {
|
|
309
|
-
this.
|
|
342
|
+
const isConfirmed = this.confirmClosing();
|
|
343
|
+
if (isConfirmed) {
|
|
344
|
+
this.config.afterClose?.();
|
|
345
|
+
}
|
|
310
346
|
}
|
|
311
347
|
};
|
|
312
348
|
get isAbleToMergeQuery() {
|
package/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.cjs","sources":["../src/core/config/config.ts","../src/core/route/route.ts","../src/core/route-group/route-group.ts","../src/core/router/router.ts","../src/core/utils/is-route-entity.ts","../src/core/virtual-route/virtual-route.ts"],"sourcesContent":["import {\n createBrowserHistory,\n type History,\n type IQueryParams,\n isObservableHistory,\n QueryParams,\n} from 'mobx-location-history';\nimport { createGlobalDynamicConfig } from 'yummies/complex';\n\nimport type { RouteGlobalConfig } from './config.types.js';\n\nlet localHistory: History | undefined;\n\nexport const routeConfig = createGlobalDynamicConfig<RouteGlobalConfig>(\n (update) => {\n if (localHistory && update?.history && isObservableHistory(localHistory)) {\n localHistory.destroy();\n }\n\n let history: History;\n\n if (update?.history) {\n history = update.history;\n } else {\n history = localHistory = createBrowserHistory();\n }\n\n let queryParams: IQueryParams;\n\n if (update?.history && !update.queryParams) {\n queryParams = new QueryParams({ history });\n } else {\n if (update?.queryParams) {\n queryParams = update.queryParams;\n } else {\n queryParams = new QueryParams({ history });\n }\n }\n\n return {\n ...update,\n history,\n location,\n queryParams,\n };\n },\n);\n","import { LinkedAbortController } from 'linked-abort-controller';\nimport {\n action,\n computed,\n makeObservable,\n observable,\n onBecomeObserved,\n onBecomeUnobserved,\n reaction,\n} from 'mobx';\nimport {\n buildSearchString,\n type History,\n type IQueryParams,\n} from 'mobx-location-history';\nimport {\n compile,\n match,\n type ParamData,\n parse,\n type TokenData,\n} from 'path-to-regexp';\nimport type { AnyObject, IsPartial, Maybe, MaybePromise } from 'yummies/types';\n\nimport { routeConfig } from '../config/index.js';\n\nimport type {\n AnyRoute,\n BeforeOpenFeedback,\n CreatedUrlOutputParams,\n InputPathParams,\n IRoute,\n ParsedPathData,\n ParsedPathParams,\n PreparedNavigationData,\n RouteConfiguration,\n RouteNavigateParams,\n UrlCreateParams,\n} from './route.types.js';\n\n/**\n * Class for creating path based route.\n *\n * [**Documentation**](https://js2me.github.io/mobx-route/core/Route.html)\n */\nexport class Route<\n TPath extends string,\n TInputParams extends InputPathParams<TPath> = InputPathParams<TPath>,\n TOutputParams extends AnyObject = ParsedPathParams<TPath>,\n TParentRoute extends Route<any, any, any, any> | null = null,\n> implements IRoute<TPath, TInputParams, TOutputParams>\n{\n protected abortController: AbortController;\n protected history: History;\n parent: TParentRoute;\n\n query: IQueryParams;\n\n private _tokenData: TokenData | undefined;\n private _matcher?: ReturnType<typeof match>;\n private _compiler?: ReturnType<typeof compile>;\n private reactionDisposer: Maybe<VoidFunction>;\n\n meta?: AnyObject;\n\n /**\n * Indicates if this route is an index route. Index routes activate when parent route path matches exactly.\n *\n * [**Documentation**](https://js2me.github.io/mobx-route/core/Route.html#isindex-boolean)\n */\n isIndex: boolean;\n\n /**\n * Indicates if this route is an hash route.\n *\n * [**Documentation**](https://js2me.github.io/mobx-route/core/Route.html#ishash-boolean)\n */\n isHash: boolean;\n\n children: AnyRoute[] = [];\n\n constructor(\n public path: TPath,\n protected config: RouteConfiguration<\n TPath,\n TInputParams,\n TOutputParams,\n TParentRoute\n > = {},\n ) {\n this.abortController = new LinkedAbortController(config.abortSignal);\n this.history = config.history ?? routeConfig.get().history;\n this.query = config.queryParams ?? routeConfig.get().queryParams;\n this.isIndex = !!this.config.index;\n this.isHash = !!this.config.hash;\n this.meta = this.config.meta;\n this.parent = config.parent ?? (null as unknown as TParentRoute);\n\n computed.struct(this, 'isOpened');\n computed.struct(this, 'data');\n computed.struct(this, 'params');\n computed.struct(this, 'currentPath');\n computed.struct(this, 'hasOpenedChildren');\n computed.struct(this, 'isAbleToMergeQuery');\n computed(this, 'baseUrl');\n\n observable(this, 'children');\n observable.ref(this, 'parent');\n action(this, 'addChildren');\n action(this, 'removeChildren');\n\n makeObservable(this);\n\n onBecomeObserved(this, 'isOpened', () => {\n if (!config.afterOpen && !config.afterClose) {\n return;\n }\n\n this.reactionDisposer = reaction(\n () => this.isOpened,\n this.processOpenedState,\n {\n signal: this.abortController.signal,\n fireImmediately: true,\n },\n );\n });\n onBecomeUnobserved(this, 'isOpened', () => {\n this.reactionDisposer?.();\n this.reactionDisposer = undefined;\n });\n }\n\n protected get baseUrl() {\n const baseUrl = this.config.baseUrl ?? routeConfig.get().baseUrl;\n return baseUrl?.endsWith('/') ? baseUrl.slice(0, -1) : baseUrl;\n }\n\n protected get parsedPathData(): ParsedPathData<TPath> | null {\n let pathnameToCheck: string;\n\n if (this.isHash) {\n pathnameToCheck = this.history.location.hash.slice(1);\n } else {\n pathnameToCheck = this.history.location.pathname;\n }\n\n if (this.baseUrl) {\n if (!this.history.location.pathname.startsWith(this.baseUrl)) {\n return null;\n }\n\n pathnameToCheck = pathnameToCheck.replace(this.baseUrl, '');\n }\n\n if (\n (this.path === '' || this.path === '/') &&\n (pathnameToCheck === '/' || pathnameToCheck === '')\n ) {\n return { params: {} as any, path: pathnameToCheck };\n }\n\n this._matcher ??= match(this.tokenData, {\n end: false,\n ...this.config.matchOptions,\n });\n const parsed = this._matcher(pathnameToCheck);\n\n if (parsed === false) {\n return null;\n }\n\n return parsed as ParsedPathData<TPath>;\n }\n\n /**\n * Matched path segment for current URL.\n *\n * [**Documentation**](https://js2me.github.io/mobx-route/core/Route.html#currentpath-parsedpathname-null)\n */\n get currentPath(): string | null {\n return this.parsedPathData?.path ?? null;\n }\n\n /**\n * Current parsed path parameters.\n *\n * [**Documentation**](https://js2me.github.io/mobx-route/core/Route.html#params-parsedpathparams-null)\n */\n get params(): TOutputParams | null {\n if (!this.parsedPathData?.params) {\n return null;\n }\n\n let params: TOutputParams | null =\n (this.parsedPathData?.params as unknown as Maybe<TOutputParams>) ?? null;\n\n if (this.config.params) {\n const result = this.config.params(\n this.parsedPathData.params,\n this.config.meta,\n );\n if (result) {\n params = result;\n } else {\n return null;\n }\n }\n\n return params;\n }\n\n /**\n * Defines the \"open\" state for this route.\n *\n * [**Documentation**](https://js2me.github.io/mobx-route/core/Route.html#isopened-boolean)\n */\n get isOpened() {\n if (this.params === null || this.parsedPathData === null) {\n return false;\n }\n\n return (\n !this.config.checkOpened || this.config.checkOpened(this.parsedPathData)\n );\n }\n\n /**\n * Allows to create child route based on this route with merging this route path and extending path.\n *\n * [**Documentation**](https://js2me.github.io/mobx-route/core/Route.html#extend-path-config-route)\n */\n extend<\n TExtendedPath extends string,\n TExtendedInputParams extends\n InputPathParams<`${TPath}${TExtendedPath}`> = InputPathParams<`${TPath}${TExtendedPath}`>,\n TExtendedOutputParams extends AnyObject = TInputParams &\n ParsedPathParams<`${TPath}${TExtendedPath}`>,\n >(\n path: TExtendedPath,\n config?: Omit<\n RouteConfiguration<\n `${TPath}${TExtendedPath}`,\n TInputParams & TExtendedInputParams,\n TExtendedOutputParams,\n any\n >,\n 'parent'\n >,\n ) {\n type ExtendedRoutePath = `${TPath}${TExtendedPath}`;\n type ParentRoute = this;\n // biome-ignore lint/correctness/noUnusedVariables: this is need to extract unused fields\n const { index, params, ...configFromCurrentRoute } = this.config;\n\n const extendedChild = new Route<\n ExtendedRoutePath,\n TInputParams & TExtendedInputParams,\n TExtendedOutputParams,\n ParentRoute\n >(`${this.path}${path}`, {\n ...configFromCurrentRoute,\n ...config,\n parent: this,\n } as any);\n\n this.addChildren(extendedChild as any);\n\n return extendedChild;\n }\n\n addChildren(...routes: AnyRoute[]) {\n this.children.push(...routes);\n }\n\n removeChildren(...routes: AnyRoute[]) {\n this.children = this.children.filter((child) => !routes.includes(child));\n }\n\n /**\n * [**Documentation**](https://js2me.github.io/mobx-route/core/Route.html#hasopenedchildren-boolean)\n */\n get hasOpenedChildren(): boolean {\n return this.children.some(\n (child) => child.isOpened || child.hasOpenedChildren,\n );\n }\n\n protected processParams(\n params?: TInputParams | null | undefined,\n ): ParamData | undefined {\n if (params == null) return undefined;\n\n return Object.entries(params).reduce((acc, [key, value]) => {\n if (value != null) {\n acc[key] = Array.isArray(value) ? value.map(String) : String(value);\n }\n return acc;\n }, {} as ParamData);\n }\n\n createUrl(\n ...args: IsPartial<TInputParams> extends true\n ? [\n params?: Maybe<TInputParams>,\n query?: Maybe<AnyObject>,\n mergeQueryOrParams?: boolean | CreatedUrlOutputParams,\n ]\n : [\n params: TInputParams,\n query?: Maybe<AnyObject>,\n mergeQueryOrParams?: boolean | CreatedUrlOutputParams,\n ]\n ) {\n const params = args[0];\n const rawQuery = args[1];\n const mergeQueryOrOutputParams = args[2] ?? this.isAbleToMergeQuery;\n const outputParams: Maybe<CreatedUrlOutputParams> =\n typeof mergeQueryOrOutputParams === 'boolean'\n ? { mergeQuery: mergeQueryOrOutputParams }\n : mergeQueryOrOutputParams;\n\n const query = outputParams?.mergeQuery\n ? { ...this.query.data, ...rawQuery }\n : (rawQuery ?? {});\n\n this._compiler ??= compile(this.tokenData);\n\n const defaultUrlCreateParams: UrlCreateParams<TInputParams> = {\n baseUrl: this.baseUrl,\n params: params as TInputParams,\n query,\n };\n const urlCreateParams: UrlCreateParams<TInputParams> =\n this.config.createUrl?.(defaultUrlCreateParams, this.query.data) ??\n routeConfig.get().createUrl?.(defaultUrlCreateParams, this.query.data) ??\n defaultUrlCreateParams;\n\n const path = this._compiler(this.processParams(urlCreateParams.params));\n\n const url = [urlCreateParams.baseUrl, this.isHash ? '#' : '', path].join(\n '',\n );\n\n if (outputParams?.omitQuery) {\n return url;\n }\n\n return `${url}${buildSearchString(urlCreateParams.query)}`;\n }\n\n /**\n * Navigates to this route.\n *\n * [**Documentation**](https://js2me.github.io/mobx-route/core/Route.html#open-args)\n */\n open(\n ...args: IsPartial<TInputParams> extends true\n ? [\n params?: TInputParams | null | undefined,\n navigateParams?: RouteNavigateParams,\n ]\n : [params: TInputParams, navigateParams?: RouteNavigateParams]\n ): Promise<void>;\n open(\n ...args: IsPartial<TInputParams> extends true\n ? [\n params?: TInputParams | null | undefined,\n replace?: RouteNavigateParams['replace'],\n query?: RouteNavigateParams['query'],\n ]\n : [\n params: TInputParams,\n replace?: RouteNavigateParams['replace'],\n query?: RouteNavigateParams['query'],\n ]\n ): Promise<void>;\n open(url: string, navigateParams?: RouteNavigateParams): Promise<void>;\n open(\n url: string,\n replace?: RouteNavigateParams['replace'],\n query?: RouteNavigateParams['query'],\n ): Promise<void>;\n\n /**\n * Navigates to this route.\n *\n * [**Documentation**](https://js2me.github.io/mobx-route/core/Route.html#open-args)\n */\n async open(...args: any[]) {\n const {\n replace,\n state: rawState,\n query: rawQuery,\n mergeQuery: rawMergeQuery,\n } = typeof args[1] === 'boolean' || args.length > 2\n ? ({ replace: args[1], query: args[2] } as RouteNavigateParams)\n : ((args[1] ?? {}) as RouteNavigateParams);\n let url: string;\n let params: Maybe<InputPathParams<TPath>>;\n\n const mergeQuery = rawMergeQuery ?? this.isAbleToMergeQuery;\n const query = mergeQuery ? { ...this.query.data, ...rawQuery } : rawQuery;\n\n if (typeof args[0] === 'string') {\n url = args[0];\n } else {\n params = args[0] as InputPathParams<TPath>;\n url = this.createUrl(args[0], query);\n }\n\n const state = rawState ?? null;\n\n const navigationData: PreparedNavigationData<TInputParams> = {\n url,\n params: params as TInputParams,\n replace,\n state,\n query,\n };\n\n const feedback = await this.beforeOpen(navigationData);\n\n if (feedback === false) {\n return;\n }\n\n if (typeof feedback === 'object') {\n Object.assign(navigationData, feedback);\n }\n\n if (replace) {\n this.history.replace(url, state);\n } else {\n this.history.push(url, state);\n }\n\n if (!this.reactionDisposer && this.isOpened) {\n this.config.afterOpen?.(this.parsedPathData!, this);\n }\n }\n\n protected beforeOpen(\n openData: PreparedNavigationData<TInputParams>,\n ): MaybePromise<BeforeOpenFeedback> {\n if (this.config.beforeOpen) {\n return this.config.beforeOpen(openData);\n }\n\n return true;\n }\n\n protected afterClose() {\n if (this.config.afterClose) {\n return this.config.afterClose();\n }\n\n return true;\n }\n\n protected get tokenData() {\n if (!this._tokenData) {\n this._tokenData = parse(this.path, this.config.parseOptions);\n }\n return this._tokenData;\n }\n\n private firstOpenedStateCheck = true;\n private processOpenedState = (isOpened: boolean) => {\n if (this.firstOpenedStateCheck) {\n this.firstOpenedStateCheck = false;\n // ignore first 'afterClose' callback call\n if (!isOpened) {\n return;\n }\n }\n\n if (isOpened) {\n this.config.afterOpen?.(this.parsedPathData!, this);\n } else {\n this.config.afterClose?.();\n }\n };\n\n private get isAbleToMergeQuery() {\n return this.config.mergeQuery ?? routeConfig.get().mergeQuery;\n }\n\n destroy() {\n this.abortController.abort();\n }\n}\n\nexport const createRoute = <\n TPath extends string,\n TInputParams extends InputPathParams<TPath> = InputPathParams<TPath>,\n TOutputParams extends AnyObject = ParsedPathParams<TPath>,\n TParentRoute extends Route<any, any, any, any> | null = null,\n>(\n path: TPath,\n config?: RouteConfiguration<TPath, TInputParams, TOutputParams, TParentRoute>,\n) => new Route<TPath, TInputParams, TOutputParams, TParentRoute>(path, config);\n","import { computed, makeObservable, observable } from 'mobx';\n\nimport type {\n AbstractRouteGroup,\n AnyRouteEntity,\n RoutesCollection,\n} from './route-group.types.js';\n\ndeclare const process: { env: { NODE_ENV?: string } };\n\n/**\n * Class for grouping related routes and managing their state.\n *\n * [**Documentation**](https://js2me.github.io/mobx-route/core/RouteGroup.html)\n */\nexport class RouteGroup<TRoutesCollection extends RoutesCollection>\n implements AbstractRouteGroup<TRoutesCollection>\n{\n routes: TRoutesCollection;\n\n constructor(\n routes: TRoutesCollection,\n private _indexRoute?: AnyRouteEntity,\n ) {\n this.routes = routes;\n\n computed.struct(this, 'isOpened');\n computed.struct(this, 'indexRoute');\n observable.shallow(this, 'routes');\n makeObservable(this);\n }\n\n /**\n * Returns true if at least one route in the group is open.\n *\n * [**Documentation**](https://js2me.github.io/mobx-route/core/RouteGroup.html#isopened-boolean)\n */\n get isOpened(): boolean {\n const routes = Object.values(this.routes);\n return routes.some(\n (route) =>\n route.isOpened ||\n ('hasOpenedChildren' in route && route.hasOpenedChildren),\n );\n }\n\n /**\n * First found index route.\n *\n * [**Documentation**](https://js2me.github.io/mobx-route/core/RouteGroup.html#indexroute-route-undefined)\n */\n get indexRoute(): AnyRouteEntity | undefined {\n return (this._indexRoute ??\n Object.values(this.routes).find(\n (route) => 'isIndex' in route && route.isIndex,\n )) as unknown as AnyRouteEntity;\n }\n\n /**\n * Main navigation method for the group.\n *\n * [**Documentation**](https://js2me.github.io/mobx-route/core/RouteGroup.html#open-args-any-void)\n */\n open(...args: any[]) {\n let lastGroupRoute: RouteGroup<any> | undefined;\n\n if (this.indexRoute && 'open' in this.indexRoute) {\n this.indexRoute.open(...args);\n return;\n }\n\n for (const routeName in this.routes) {\n const route = this.routes[routeName];\n if (route instanceof RouteGroup) {\n lastGroupRoute = route;\n }\n }\n\n if (lastGroupRoute) {\n lastGroupRoute.open(...args);\n } else if (process.env.NODE_ENV !== 'production') {\n console.warn(\n \"RouteGroup doesn't have index route. open() method doesn't work.\",\n );\n }\n }\n}\n\nexport const createRouteGroup = <TRoutesCollection extends RoutesCollection>(\n routes: TRoutesCollection,\n indexRoute?: AnyRouteEntity,\n) => new RouteGroup<TRoutesCollection>(routes, indexRoute);\n","import { computed, makeObservable } from 'mobx';\nimport {\n buildSearchString,\n type History,\n type IQueryParams,\n} from 'mobx-location-history';\n\nimport { routeConfig } from '../config/index.js';\nimport type { RoutesCollection } from '../route-group/index.js';\n\nimport type {\n RouterConfiguration,\n RouterNavigateOptions,\n} from './router.types.js';\n\n/**\n * Class for centralized routing management.\n *\n * [**Documentation**](https://js2me.github.io/mobx-route/core/Router.html)\n */\nexport class Router<TRoutesCollection extends RoutesCollection> {\n routes: TRoutesCollection;\n history: History;\n query: IQueryParams;\n\n constructor(config: RouterConfiguration<TRoutesCollection>) {\n this.routes = config.routes;\n this.history = config.history ?? routeConfig.get().history;\n this.query = config.queryParams ?? routeConfig.get().queryParams;\n\n computed.struct(this, 'location');\n\n makeObservable(this);\n }\n\n get location() {\n return this.history.location;\n }\n\n navigate(url: string, options?: RouterNavigateOptions) {\n const query =\n (options?.mergeQuery ?? routeConfig.get().mergeQuery)\n ? { ...this.query.data, ...options?.query }\n : { ...options?.query };\n\n const searchString = buildSearchString(query);\n const navigationUrl = `${url}${searchString}`;\n\n if (options?.replace) {\n this.history.replace(navigationUrl, options?.state);\n } else {\n this.history.push(navigationUrl, options?.state);\n }\n }\n}\n\nexport const createRouter = <TRoutesCollection extends RoutesCollection>(\n config: RouterConfiguration<TRoutesCollection>,\n) => new Router(config);\n","import type { AnyRouteEntity } from '../route-group/index.js';\n\nexport const isRouteEntity = (route: any): route is AnyRouteEntity =>\n route && 'isOpened' in route;\n","import { LinkedAbortController } from 'linked-abort-controller';\nimport {\n action,\n computed,\n makeObservable,\n observable,\n onBecomeObserved,\n onBecomeUnobserved,\n reaction,\n runInAction,\n} from 'mobx';\nimport type { IQueryParams } from 'mobx-location-history';\nimport { callFunction } from 'yummies/common';\nimport type { AnyObject, EmptyObject, IsPartial, Maybe } from 'yummies/types';\n\nimport { routeConfig } from '../config/index.js';\n\nimport type {\n AbstractVirtualRoute,\n VirtualOpenExtraParams,\n VirtualRouteConfiguration,\n} from './virtual-route.types.js';\n\n/**\n * Class for creating routes with custom activation logic\n *\n * [**Documentation**](https://js2me.github.io/mobx-route/core/VirtualRoute.html)\n */\nexport class VirtualRoute<TParams extends AnyObject | EmptyObject = EmptyObject>\n implements AbstractVirtualRoute<TParams>\n{\n protected abortController: AbortController;\n query: IQueryParams;\n params: TParams | null;\n\n private isLocalOpened: boolean;\n\n private openChecker: Maybe<VirtualRouteConfiguration<TParams>['checkOpened']>;\n private reactionDisposer: Maybe<VoidFunction>;\n\n constructor(protected config: VirtualRouteConfiguration<TParams> = {}) {\n this.abortController = new LinkedAbortController(config.abortSignal);\n this.query = config.queryParams ?? routeConfig.get().queryParams;\n this.params = callFunction(config.initialParams, this) ?? null;\n this.openChecker = config.checkOpened;\n this.isLocalOpened = this.openChecker?.(this) ?? false;\n\n observable(this, 'params');\n observable.ref(this, 'isLocalOpened');\n observable.ref(this, '_isOpened');\n computed.struct(this, 'isOpened');\n action(this, 'setOpenChecker');\n action(this, 'open');\n action(this, 'close');\n makeObservable(this);\n\n onBecomeObserved(this, 'isOpened', () => {\n if (!config.afterOpen && !config.afterClose) {\n return;\n }\n\n this.reactionDisposer = reaction(\n () => this.isOpened,\n this.processOpenedState,\n {\n signal: this.abortController.signal,\n fireImmediately: true,\n },\n );\n });\n onBecomeUnobserved(this, 'isOpened', () => {\n this.reactionDisposer?.();\n this.reactionDisposer = undefined;\n });\n }\n\n /**\n * [**Documentation**](https://js2me.github.io/mobx-route/core/VirtualRoute.html#isopened-boolean)\n */\n get isOpened() {\n const isOuterOpened = this.openChecker == null || this.openChecker(this);\n return this.isLocalOpened && isOuterOpened;\n }\n\n /**\n * [**Documentation**](https://js2me.github.io/mobx-route/core/VirtualRoute.html#setopenchecker-openchecker-void)\n */\n setOpenChecker(\n openChecker: Maybe<VirtualRouteConfiguration<TParams>['checkOpened']>,\n ) {\n this.openChecker = openChecker;\n }\n\n /**\n * [**Documentation**](https://js2me.github.io/mobx-route/core/VirtualRoute.html#open-params-extraparams-query-replace-promise-void)\n */\n open(\n ...args: IsPartial<TParams> extends true\n ? [params?: Maybe<TParams>, extraParams?: VirtualOpenExtraParams]\n : [params: TParams, extraParams?: VirtualOpenExtraParams]\n ): Promise<void>;\n async open(...args: any[]) {\n const params = (args[0] ?? {}) as unknown as TParams;\n const extraParams: Maybe<VirtualOpenExtraParams> = args[1];\n\n if (this.config.beforeOpen) {\n const beforeOpenResult = await this.config.beforeOpen(params, this);\n if (beforeOpenResult === false) {\n return;\n }\n }\n\n if (this.config.open == null) {\n runInAction(() => {\n this.isLocalOpened = true;\n });\n } else {\n const result = await this.config.open(params, this);\n // because result can return void so this is truthy for opening state\n runInAction(() => {\n this.isLocalOpened = result !== false;\n });\n }\n\n if (!this.isLocalOpened) {\n return;\n }\n\n if (extraParams?.query) {\n this.query.update(extraParams.query, extraParams.replace);\n }\n\n runInAction(() => {\n this.params = params;\n });\n\n if (!this.reactionDisposer && this.isOpened) {\n this.config.afterOpen?.(this.params!, this);\n }\n }\n\n /**\n * [**Documentation**](https://js2me.github.io/mobx-route/core/VirtualRoute.html#close-void)\n */\n close() {\n if (this.config.close == null) {\n this.isLocalOpened = false;\n } else {\n const result = this.config.close(this);\n // because result can return void so this is truthy for opening state\n this.isLocalOpened = result !== false;\n }\n\n this.params = null;\n }\n\n private firstOpenedStateCheck = true;\n private processOpenedState = (isOpened: boolean) => {\n if (this.firstOpenedStateCheck) {\n this.firstOpenedStateCheck = false;\n // ignore first 'afterClose' callback call\n if (!isOpened) {\n return;\n }\n }\n\n if (isOpened) {\n this.config.afterOpen?.(this.params!, this);\n } else {\n this.config.afterClose?.();\n }\n };\n\n destroy() {\n this.abortController.abort();\n }\n}\n\nexport const createVirtualRoute = <\n TParams extends AnyObject | EmptyObject = EmptyObject,\n>(\n config?: VirtualRouteConfiguration<TParams>,\n) => new VirtualRoute<TParams>(config);\n"],"names":["createGlobalDynamicConfig","isObservableHistory","createBrowserHistory","QueryParams","LinkedAbortController","computed","observable","action","makeObservable","onBecomeObserved","reaction","onBecomeUnobserved","match","compile","buildSearchString","parse","callFunction","runInAction"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.cjs","sources":["../src/core/config/config.ts","../src/core/route/route.ts","../src/core/route-group/route-group.ts","../src/core/router/router.ts","../src/core/utils/is-route-entity.ts","../src/core/virtual-route/virtual-route.ts"],"sourcesContent":["import {\n createBrowserHistory,\n type History,\n type IQueryParams,\n isObservableHistory,\n QueryParams,\n} from 'mobx-location-history';\nimport { createGlobalDynamicConfig } from 'yummies/complex';\n\nimport type { RouteGlobalConfig } from './config.types.js';\n\nlet localHistory: History | undefined;\n\nexport const routeConfig = createGlobalDynamicConfig<RouteGlobalConfig>(\n (update) => {\n if (localHistory && update?.history && isObservableHistory(localHistory)) {\n localHistory.destroy();\n }\n\n let history: History;\n\n if (update?.history) {\n history = update.history;\n } else {\n history = localHistory = createBrowserHistory();\n }\n\n let queryParams: IQueryParams;\n\n if (update?.history && !update.queryParams) {\n queryParams = new QueryParams({ history });\n } else {\n if (update?.queryParams) {\n queryParams = update.queryParams;\n } else {\n queryParams = new QueryParams({ history });\n }\n }\n\n return {\n ...update,\n history,\n location,\n queryParams,\n };\n },\n Symbol.for('MOBX_ROUTE_CONFIG'),\n);\n","import { LinkedAbortController } from 'linked-abort-controller';\nimport {\n action,\n computed,\n makeObservable,\n observable,\n reaction,\n runInAction,\n} from 'mobx';\nimport {\n buildSearchString,\n type History,\n type IQueryParams,\n} from 'mobx-location-history';\nimport {\n compile,\n match,\n type ParamData,\n parse,\n type TokenData,\n} from 'path-to-regexp';\nimport type { AnyObject, IsPartial, Maybe } from 'yummies/types';\nimport { routeConfig } from '../config/index.js';\nimport type {\n AnyRoute,\n CreatedUrlOutputParams,\n InputPathParams,\n IRoute,\n NavigationTrx,\n ParsedPathData,\n ParsedPathParams,\n RouteConfiguration,\n RouteNavigateParams,\n UrlCreateParams,\n} from './route.types.js';\n\n/**\n * Class for creating path based route.\n *\n * [**Documentation**](https://js2me.github.io/mobx-route/core/Route.html)\n */\nexport class Route<\n TPath extends string,\n TInputParams extends InputPathParams<TPath> = InputPathParams<TPath>,\n TOutputParams extends AnyObject = ParsedPathParams<TPath>,\n TParentRoute extends Route<any, any, any, any> | null = null,\n> implements IRoute<TPath, TInputParams, TOutputParams>\n{\n protected abortController: AbortController;\n protected history: History;\n parent: TParentRoute;\n\n query: IQueryParams;\n\n private _tokenData: TokenData | undefined;\n private _matcher?: ReturnType<typeof match>;\n private _compiler?: ReturnType<typeof compile>;\n private skipPathMatchCheck = false;\n\n protected status:\n | 'opening'\n | 'closed'\n | 'open-rejected'\n | 'open-confirmed'\n | 'unknown';\n\n meta?: AnyObject;\n\n /**\n * Indicates if this route is an index route. Index routes activate when parent route path matches exactly.\n *\n * [**Documentation**](https://js2me.github.io/mobx-route/core/Route.html#isindex-boolean)\n */\n isIndex: boolean;\n\n /**\n * Indicates if this route is an hash route.\n *\n * [**Documentation**](https://js2me.github.io/mobx-route/core/Route.html#ishash-boolean)\n */\n isHash: boolean;\n\n children: AnyRoute[] = [];\n\n constructor(\n public path: TPath,\n protected config: RouteConfiguration<\n TPath,\n TInputParams,\n TOutputParams,\n TParentRoute\n > = {},\n ) {\n this.abortController = new LinkedAbortController(config.abortSignal);\n this.history = config.history ?? routeConfig.get().history;\n this.query = config.queryParams ?? routeConfig.get().queryParams;\n this.isIndex = !!this.config.index;\n this.isHash = !!this.config.hash;\n this.meta = this.config.meta;\n this.status = 'unknown';\n this.parent = config.parent ?? (null as unknown as TParentRoute);\n\n computed(this, 'isPathMatched');\n computed(this, 'isOpened');\n computed.struct(this, 'data');\n computed.struct(this, 'params');\n computed(this, 'currentPath');\n computed(this, 'hasOpenedChildren');\n computed(this, 'isAbleToMergeQuery');\n computed(this, 'baseUrl');\n\n observable(this, 'children');\n observable.ref(this, 'parent');\n observable.ref(this, 'status');\n computed(this, 'isOpening');\n action(this, 'addChildren');\n action(this, 'confirmOpening');\n action(this, 'confirmClosing');\n action(this, 'removeChildren');\n\n makeObservable(this);\n\n reaction(() => this.isPathMatched, this.checkPathMatch, {\n signal: this.abortController.signal,\n fireImmediately: true,\n });\n }\n\n protected get baseUrl() {\n const baseUrl = this.config.baseUrl ?? routeConfig.get().baseUrl;\n return baseUrl?.endsWith('/') ? baseUrl.slice(0, -1) : baseUrl;\n }\n\n protected get parsedPathData(): ParsedPathData<TPath> | null {\n let pathnameToCheck: string;\n\n if (this.isHash) {\n pathnameToCheck = this.history.location.hash.slice(1);\n } else {\n pathnameToCheck = this.history.location.pathname;\n }\n\n if (this.baseUrl) {\n if (!this.history.location.pathname.startsWith(this.baseUrl)) {\n return null;\n }\n\n pathnameToCheck = pathnameToCheck.replace(this.baseUrl, '');\n }\n\n if (\n (this.path === '' || this.path === '/') &&\n (pathnameToCheck === '/' || pathnameToCheck === '')\n ) {\n return { params: {} as any, path: pathnameToCheck };\n }\n\n this._matcher ??= match(this.tokenData, {\n end: this.config.exact ?? false,\n ...this.config.matchOptions,\n });\n const parsed = this._matcher(pathnameToCheck);\n\n if (parsed === false) {\n return null;\n }\n\n return parsed as ParsedPathData<TPath>;\n }\n\n get isOpening() {\n return this.status === 'opening';\n }\n\n /**\n * Matched path segment for current URL.\n *\n * [**Documentation**](https://js2me.github.io/mobx-route/core/Route.html#currentpath-parsedpathname-null)\n */\n get currentPath(): string | null {\n return this.parsedPathData?.path ?? null;\n }\n\n /**\n * Current parsed path parameters.\n *\n * [**Documentation**](https://js2me.github.io/mobx-route/core/Route.html#params-parsedpathparams-null)\n */\n get params(): TOutputParams | null {\n if (!this.parsedPathData?.params) {\n return null;\n }\n\n let params: TOutputParams | null =\n (this.parsedPathData?.params as unknown as Maybe<TOutputParams>) ?? null;\n\n if (this.config.params) {\n const result = this.config.params(\n this.parsedPathData.params,\n this.config.meta,\n );\n if (result) {\n params = result;\n } else {\n return null;\n }\n }\n\n return params;\n }\n\n protected get isPathMatched() {\n return this.parsedPathData !== null;\n }\n\n /**\n * Defines the \"open\" state for this route.\n *\n * [**Documentation**](https://js2me.github.io/mobx-route/core/Route.html#isopened-boolean)\n */\n get isOpened() {\n if (\n !this.isPathMatched ||\n this.params === null ||\n this.status !== 'open-confirmed'\n ) {\n return false;\n }\n\n return (\n !this.config.checkOpened || this.config.checkOpened(this.parsedPathData!)\n );\n }\n\n /**\n * Allows to create child route based on this route with merging this route path and extending path.\n *\n * [**Documentation**](https://js2me.github.io/mobx-route/core/Route.html#extend-path-config-route)\n */\n extend<\n TExtendedPath extends string,\n TExtendedInputParams extends\n InputPathParams<`${TPath}${TExtendedPath}`> = InputPathParams<`${TPath}${TExtendedPath}`>,\n TExtendedOutputParams extends AnyObject = TInputParams &\n ParsedPathParams<`${TPath}${TExtendedPath}`>,\n >(\n path: TExtendedPath,\n config?: Omit<\n RouteConfiguration<\n `${TPath}${TExtendedPath}`,\n TInputParams & TExtendedInputParams,\n TExtendedOutputParams,\n any\n >,\n 'parent'\n >,\n ) {\n type ExtendedRoutePath = `${TPath}${TExtendedPath}`;\n type ParentRoute = this;\n // biome-ignore lint/correctness/noUnusedVariables: this is need to extract unused fields\n const { index, params, ...configFromCurrentRoute } = this.config;\n\n const extendedChild = new Route<\n ExtendedRoutePath,\n TInputParams & TExtendedInputParams,\n TExtendedOutputParams,\n ParentRoute\n >(`${this.path}${path}`, {\n ...configFromCurrentRoute,\n ...config,\n parent: this,\n } as any);\n\n this.addChildren(extendedChild as any);\n\n return extendedChild;\n }\n\n addChildren(...routes: AnyRoute[]) {\n this.children.push(...routes);\n }\n\n removeChildren(...routes: AnyRoute[]) {\n this.children = this.children.filter((child) => !routes.includes(child));\n }\n\n /**\n * [**Documentation**](https://js2me.github.io/mobx-route/core/Route.html#hasopenedchildren-boolean)\n */\n get hasOpenedChildren(): boolean {\n return this.children.some(\n (child) => child.isOpened || child.hasOpenedChildren,\n );\n }\n\n protected processParams(\n params?: TInputParams | null | undefined,\n ): ParamData | undefined {\n if (params == null) return undefined;\n\n return Object.entries(params).reduce((acc, [key, value]) => {\n if (value != null) {\n acc[key] = Array.isArray(value) ? value.map(String) : String(value);\n }\n return acc;\n }, {} as ParamData);\n }\n\n createUrl(\n ...args: IsPartial<TInputParams> extends true\n ? [\n params?: Maybe<TInputParams>,\n query?: Maybe<AnyObject>,\n mergeQueryOrParams?: boolean | CreatedUrlOutputParams,\n ]\n : [\n params: TInputParams,\n query?: Maybe<AnyObject>,\n mergeQueryOrParams?: boolean | CreatedUrlOutputParams,\n ]\n ) {\n const params = args[0];\n const rawQuery = args[1];\n const mergeQueryOrOutputParams = args[2] ?? this.isAbleToMergeQuery;\n const outputParams: Maybe<CreatedUrlOutputParams> =\n typeof mergeQueryOrOutputParams === 'boolean'\n ? { mergeQuery: mergeQueryOrOutputParams }\n : mergeQueryOrOutputParams;\n\n const query = outputParams?.mergeQuery\n ? { ...this.query.data, ...rawQuery }\n : (rawQuery ?? {});\n\n this._compiler ??= compile(this.tokenData);\n\n const defaultUrlCreateParams: UrlCreateParams<TInputParams> = {\n baseUrl: this.baseUrl,\n params: params as TInputParams,\n query,\n };\n const urlCreateParams: UrlCreateParams<TInputParams> =\n this.config.createUrl?.(defaultUrlCreateParams, this.query.data) ??\n routeConfig.get().createUrl?.(defaultUrlCreateParams, this.query.data) ??\n defaultUrlCreateParams;\n\n const path = this._compiler(this.processParams(urlCreateParams.params));\n\n const url = `${urlCreateParams.baseUrl || ''}${this.isHash ? '#' : ''}${path}`;\n\n if (outputParams?.omitQuery) {\n return url;\n }\n\n return `${url}${buildSearchString(urlCreateParams.query)}`;\n }\n\n /**\n * Navigates to this route.\n *\n * [**Documentation**](https://js2me.github.io/mobx-route/core/Route.html#open-args)\n */\n open(\n ...args: IsPartial<TInputParams> extends true\n ? [\n params?: TInputParams | null | undefined,\n navigateParams?: RouteNavigateParams,\n ]\n : [params: TInputParams, navigateParams?: RouteNavigateParams]\n ): Promise<void>;\n open(\n ...args: IsPartial<TInputParams> extends true\n ? [\n params?: TInputParams | null | undefined,\n replace?: RouteNavigateParams['replace'],\n query?: RouteNavigateParams['query'],\n ]\n : [\n params: TInputParams,\n replace?: RouteNavigateParams['replace'],\n query?: RouteNavigateParams['query'],\n ]\n ): Promise<void>;\n open(url: string, navigateParams?: RouteNavigateParams): Promise<void>;\n open(\n url: string,\n replace?: RouteNavigateParams['replace'],\n query?: RouteNavigateParams['query'],\n ): Promise<void>;\n\n /**\n * Navigates to this route.\n *\n * [**Documentation**](https://js2me.github.io/mobx-route/core/Route.html#open-args)\n */\n async open(...args: any[]) {\n const {\n replace,\n state: rawState,\n query: rawQuery,\n mergeQuery: rawMergeQuery,\n } = typeof args[1] === 'boolean' || args.length > 2\n ? ({ replace: args[1], query: args[2] } as RouteNavigateParams)\n : ((args[1] ?? {}) as RouteNavigateParams);\n let url: string;\n let params: Maybe<InputPathParams<TPath>>;\n\n const mergeQuery = rawMergeQuery ?? this.isAbleToMergeQuery;\n const query = mergeQuery ? { ...this.query.data, ...rawQuery } : rawQuery;\n\n if (typeof args[0] === 'string') {\n url = args[0];\n } else {\n params = args[0] as InputPathParams<TPath>;\n url = this.createUrl(args[0], query);\n }\n\n const state = rawState ?? null;\n\n const trx: NavigationTrx<TInputParams> = {\n url,\n params: params as TInputParams,\n replace,\n state,\n query,\n };\n\n const isConfirmed = await this.confirmOpening(trx);\n\n if (!isConfirmed) {\n return;\n }\n\n this.skipPathMatchCheck = true;\n\n if (trx.replace) {\n this.history.replace(trx.url, trx.state);\n } else {\n this.history.push(trx.url, trx.state);\n }\n }\n\n protected get tokenData() {\n if (!this._tokenData) {\n this._tokenData = parse(this.path, this.config.parseOptions);\n }\n return this._tokenData;\n }\n\n protected async confirmOpening(trx: NavigationTrx<TInputParams>) {\n this.status = 'opening';\n\n if (this.config.beforeOpen) {\n const feedback = await this.config.beforeOpen(trx);\n\n if (feedback === false) {\n runInAction(() => {\n this.status = 'open-rejected';\n });\n return false;\n }\n\n if (typeof feedback === 'object') {\n runInAction(() => {\n this.status = 'open-confirmed';\n });\n\n return Object.assign(trx, feedback);\n }\n }\n\n runInAction(() => {\n this.status = 'open-confirmed';\n });\n\n return true;\n }\n\n protected confirmClosing() {\n this.status = 'closed';\n return true;\n }\n\n private firstPathMatchingRun = true;\n\n private checkPathMatch = async (isPathMathched: boolean) => {\n if (this.firstPathMatchingRun) {\n this.firstPathMatchingRun = false;\n // ignore first 'afterClose' callback call\n if (!isPathMathched) {\n return;\n }\n }\n\n if (this.skipPathMatchCheck) {\n // after open\n this.skipPathMatchCheck = false;\n return;\n }\n\n if (isPathMathched) {\n const trx: NavigationTrx<TInputParams> = {\n url: this.parsedPathData!.path,\n params: this.parsedPathData!.params as TInputParams,\n state: this.history.location.state,\n query: this.query.data,\n };\n\n const nextTrxOrConfirmed = await this.confirmOpening(trx);\n\n if (!nextTrxOrConfirmed) {\n return;\n }\n\n this.config.afterOpen?.(this.parsedPathData!, this);\n\n if (typeof nextTrxOrConfirmed === 'object') {\n if (nextTrxOrConfirmed.replace) {\n this.history.replace(\n nextTrxOrConfirmed.url,\n nextTrxOrConfirmed.state,\n );\n } else {\n this.history.push(nextTrxOrConfirmed.url, nextTrxOrConfirmed.state);\n }\n }\n\n return;\n } else {\n const isConfirmed = this.confirmClosing();\n\n if (isConfirmed) {\n this.config.afterClose?.();\n }\n }\n };\n\n private get isAbleToMergeQuery() {\n return this.config.mergeQuery ?? routeConfig.get().mergeQuery;\n }\n\n destroy() {\n this.abortController.abort();\n }\n}\n\nexport const createRoute = <\n TPath extends string,\n TInputParams extends InputPathParams<TPath> = InputPathParams<TPath>,\n TOutputParams extends AnyObject = ParsedPathParams<TPath>,\n TParentRoute extends Route<any, any, any, any> | null = null,\n>(\n path: TPath,\n config?: RouteConfiguration<TPath, TInputParams, TOutputParams, TParentRoute>,\n) => new Route<TPath, TInputParams, TOutputParams, TParentRoute>(path, config);\n","import { computed, makeObservable, observable } from 'mobx';\n\nimport type {\n AbstractRouteGroup,\n AnyRouteEntity,\n RoutesCollection,\n} from './route-group.types.js';\n\ndeclare const process: { env: { NODE_ENV?: string } };\n\n/**\n * Class for grouping related routes and managing their state.\n *\n * [**Documentation**](https://js2me.github.io/mobx-route/core/RouteGroup.html)\n */\nexport class RouteGroup<TRoutesCollection extends RoutesCollection>\n implements AbstractRouteGroup<TRoutesCollection>\n{\n routes: TRoutesCollection;\n\n constructor(\n routes: TRoutesCollection,\n private _indexRoute?: AnyRouteEntity,\n ) {\n this.routes = routes;\n\n computed.struct(this, 'isOpened');\n computed.struct(this, 'indexRoute');\n observable.shallow(this, 'routes');\n makeObservable(this);\n }\n\n /**\n * Returns true if at least one route in the group is open.\n *\n * [**Documentation**](https://js2me.github.io/mobx-route/core/RouteGroup.html#isopened-boolean)\n */\n get isOpened(): boolean {\n const routes = Object.values(this.routes);\n return routes.some(\n (route) =>\n route.isOpened ||\n ('hasOpenedChildren' in route && route.hasOpenedChildren),\n );\n }\n\n /**\n * First found index route.\n *\n * [**Documentation**](https://js2me.github.io/mobx-route/core/RouteGroup.html#indexroute-route-undefined)\n */\n get indexRoute(): AnyRouteEntity | undefined {\n return (this._indexRoute ??\n Object.values(this.routes).find(\n (route) => 'isIndex' in route && route.isIndex,\n )) as unknown as AnyRouteEntity;\n }\n\n /**\n * Main navigation method for the group.\n *\n * [**Documentation**](https://js2me.github.io/mobx-route/core/RouteGroup.html#open-args-any-void)\n */\n open(...args: any[]) {\n let lastGroupRoute: RouteGroup<any> | undefined;\n\n if (this.indexRoute && 'open' in this.indexRoute) {\n this.indexRoute.open(...args);\n return;\n }\n\n for (const routeName in this.routes) {\n const route = this.routes[routeName];\n if (route instanceof RouteGroup) {\n lastGroupRoute = route;\n }\n }\n\n if (lastGroupRoute) {\n lastGroupRoute.open(...args);\n } else if (process.env.NODE_ENV !== 'production') {\n console.warn(\n \"RouteGroup doesn't have index route. open() method doesn't work.\",\n );\n }\n }\n}\n\nexport const createRouteGroup = <TRoutesCollection extends RoutesCollection>(\n routes: TRoutesCollection,\n indexRoute?: AnyRouteEntity,\n) => new RouteGroup<TRoutesCollection>(routes, indexRoute);\n","import { computed, makeObservable } from 'mobx';\nimport {\n buildSearchString,\n type History,\n type IQueryParams,\n} from 'mobx-location-history';\n\nimport { routeConfig } from '../config/index.js';\nimport type { RoutesCollection } from '../route-group/index.js';\n\nimport type {\n RouterConfiguration,\n RouterNavigateOptions,\n} from './router.types.js';\n\n/**\n * Class for centralized routing management.\n *\n * [**Documentation**](https://js2me.github.io/mobx-route/core/Router.html)\n */\nexport class Router<TRoutesCollection extends RoutesCollection> {\n routes: TRoutesCollection;\n history: History;\n query: IQueryParams;\n\n constructor(config: RouterConfiguration<TRoutesCollection>) {\n this.routes = config.routes;\n this.history = config.history ?? routeConfig.get().history;\n this.query = config.queryParams ?? routeConfig.get().queryParams;\n\n computed.struct(this, 'location');\n\n makeObservable(this);\n }\n\n get location() {\n return this.history.location;\n }\n\n navigate(url: string, options?: RouterNavigateOptions) {\n const query =\n (options?.mergeQuery ?? routeConfig.get().mergeQuery)\n ? { ...this.query.data, ...options?.query }\n : { ...options?.query };\n\n const searchString = buildSearchString(query);\n const navigationUrl = `${url}${searchString}`;\n\n if (options?.replace) {\n this.history.replace(navigationUrl, options?.state);\n } else {\n this.history.push(navigationUrl, options?.state);\n }\n }\n}\n\nexport const createRouter = <TRoutesCollection extends RoutesCollection>(\n config: RouterConfiguration<TRoutesCollection>,\n) => new Router(config);\n","import type { AnyRouteEntity } from '../route-group/index.js';\n\nexport const isRouteEntity = (route: any): route is AnyRouteEntity =>\n route && 'isOpened' in route;\n","import { LinkedAbortController } from 'linked-abort-controller';\nimport {\n action,\n computed,\n makeObservable,\n observable,\n onBecomeObserved,\n onBecomeUnobserved,\n reaction,\n runInAction,\n} from 'mobx';\nimport type { IQueryParams } from 'mobx-location-history';\nimport { callFunction } from 'yummies/common';\nimport type { AnyObject, EmptyObject, IsPartial, Maybe } from 'yummies/types';\n\nimport { routeConfig } from '../config/index.js';\n\nimport type {\n AbstractVirtualRoute,\n VirtualOpenExtraParams,\n VirtualRouteConfiguration,\n} from './virtual-route.types.js';\n\n/**\n * Class for creating routes with custom activation logic\n *\n * [**Documentation**](https://js2me.github.io/mobx-route/core/VirtualRoute.html)\n */\nexport class VirtualRoute<TParams extends AnyObject | EmptyObject = EmptyObject>\n implements AbstractVirtualRoute<TParams>\n{\n protected abortController: AbortController;\n query: IQueryParams;\n params: TParams | null;\n\n private isLocalOpened: boolean;\n\n private openChecker: Maybe<VirtualRouteConfiguration<TParams>['checkOpened']>;\n private reactionDisposer: Maybe<VoidFunction>;\n\n constructor(protected config: VirtualRouteConfiguration<TParams> = {}) {\n this.abortController = new LinkedAbortController(config.abortSignal);\n this.query = config.queryParams ?? routeConfig.get().queryParams;\n this.params = callFunction(config.initialParams, this) ?? null;\n this.openChecker = config.checkOpened;\n this.isLocalOpened = this.openChecker?.(this) ?? false;\n\n observable(this, 'params');\n observable.ref(this, 'isLocalOpened');\n observable.ref(this, '_isOpened');\n computed.struct(this, 'isOpened');\n action(this, 'setOpenChecker');\n action(this, 'open');\n action(this, 'close');\n makeObservable(this);\n\n onBecomeObserved(this, 'isOpened', () => {\n if (!config.afterOpen && !config.afterClose) {\n return;\n }\n\n this.reactionDisposer = reaction(\n () => this.isOpened,\n this.processOpenedState,\n {\n signal: this.abortController.signal,\n fireImmediately: true,\n },\n );\n });\n onBecomeUnobserved(this, 'isOpened', () => {\n this.reactionDisposer?.();\n this.reactionDisposer = undefined;\n });\n }\n\n /**\n * [**Documentation**](https://js2me.github.io/mobx-route/core/VirtualRoute.html#isopened-boolean)\n */\n get isOpened() {\n const isOuterOpened = this.openChecker == null || this.openChecker(this);\n return this.isLocalOpened && isOuterOpened;\n }\n\n /**\n * [**Documentation**](https://js2me.github.io/mobx-route/core/VirtualRoute.html#setopenchecker-openchecker-void)\n */\n setOpenChecker(\n openChecker: Maybe<VirtualRouteConfiguration<TParams>['checkOpened']>,\n ) {\n this.openChecker = openChecker;\n }\n\n /**\n * [**Documentation**](https://js2me.github.io/mobx-route/core/VirtualRoute.html#open-params-extraparams-query-replace-promise-void)\n */\n open(\n ...args: IsPartial<TParams> extends true\n ? [params?: Maybe<TParams>, extraParams?: VirtualOpenExtraParams]\n : [params: TParams, extraParams?: VirtualOpenExtraParams]\n ): Promise<void>;\n async open(...args: any[]) {\n const params = (args[0] ?? {}) as unknown as TParams;\n const extraParams: Maybe<VirtualOpenExtraParams> = args[1];\n\n if (this.config.beforeOpen) {\n const beforeOpenResult = await this.config.beforeOpen(params, this);\n if (beforeOpenResult === false) {\n return;\n }\n }\n\n if (this.config.open == null) {\n runInAction(() => {\n this.isLocalOpened = true;\n });\n } else {\n const result = await this.config.open(params, this);\n // because result can return void so this is truthy for opening state\n runInAction(() => {\n this.isLocalOpened = result !== false;\n });\n }\n\n if (!this.isLocalOpened) {\n return;\n }\n\n if (extraParams?.query) {\n this.query.update(extraParams.query, extraParams.replace);\n }\n\n runInAction(() => {\n this.params = params;\n });\n\n if (!this.reactionDisposer && this.isOpened) {\n this.config.afterOpen?.(this.params!, this);\n }\n }\n\n /**\n * [**Documentation**](https://js2me.github.io/mobx-route/core/VirtualRoute.html#close-void)\n */\n close() {\n if (this.config.close == null) {\n this.isLocalOpened = false;\n } else {\n const result = this.config.close(this);\n // because result can return void so this is truthy for opening state\n this.isLocalOpened = result !== false;\n }\n\n this.params = null;\n }\n\n private firstOpenedStateCheck = true;\n private processOpenedState = (isOpened: boolean) => {\n if (this.firstOpenedStateCheck) {\n this.firstOpenedStateCheck = false;\n // ignore first 'afterClose' callback call\n if (!isOpened) {\n return;\n }\n }\n\n if (isOpened) {\n this.config.afterOpen?.(this.params!, this);\n } else {\n this.config.afterClose?.();\n }\n };\n\n destroy() {\n this.abortController.abort();\n }\n}\n\nexport const createVirtualRoute = <\n TParams extends AnyObject | EmptyObject = EmptyObject,\n>(\n config?: VirtualRouteConfiguration<TParams>,\n) => new VirtualRoute<TParams>(config);\n"],"names":["createGlobalDynamicConfig","isObservableHistory","createBrowserHistory","QueryParams","LinkedAbortController","computed","observable","action","makeObservable","reaction","match","compile","buildSearchString","parse","runInAction","callFunction","onBecomeObserved","onBecomeUnobserved"],"mappings":"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"}
|
package/index.d.ts
CHANGED
|
@@ -138,7 +138,7 @@ declare class RouteGroup<TRoutesCollection extends RoutesCollection> implements
|
|
|
138
138
|
}
|
|
139
139
|
declare const createRouteGroup: <TRoutesCollection extends RoutesCollection>(routes: TRoutesCollection, indexRoute?: AnyRouteEntity) => RouteGroup<TRoutesCollection>;
|
|
140
140
|
|
|
141
|
-
type
|
|
141
|
+
type NavigationTrx<TParams extends AnyObject = AnyObject> = {
|
|
142
142
|
state?: any;
|
|
143
143
|
/**
|
|
144
144
|
* path parameters
|
|
@@ -153,11 +153,7 @@ type PreparedNavigationData<TParams extends AnyObject = AnyObject> = {
|
|
|
153
153
|
/**
|
|
154
154
|
* Returning `false` means ignore navigation
|
|
155
155
|
*/
|
|
156
|
-
type BeforeOpenFeedback = void | boolean |
|
|
157
|
-
url: string;
|
|
158
|
-
state?: any;
|
|
159
|
-
replace?: boolean;
|
|
160
|
-
};
|
|
156
|
+
type BeforeOpenFeedback = void | boolean | Pick<NavigationTrx, 'url' | 'state' | 'replace'>;
|
|
161
157
|
interface UrlCreateParams<TInputParams> {
|
|
162
158
|
baseUrl?: string | undefined;
|
|
163
159
|
params: TInputParams;
|
|
@@ -175,6 +171,11 @@ interface RouteConfiguration<TPath extends string, TInputParams extends InputPat
|
|
|
175
171
|
abortSignal?: AbortSignal;
|
|
176
172
|
index?: boolean;
|
|
177
173
|
hash?: boolean;
|
|
174
|
+
/**
|
|
175
|
+
* Exact match for the path
|
|
176
|
+
* @default false
|
|
177
|
+
*/
|
|
178
|
+
exact?: boolean;
|
|
178
179
|
/**
|
|
179
180
|
* [**Documentation**](https://js2me.github.io/mobx-route/core/Route.html#meta)
|
|
180
181
|
*/
|
|
@@ -194,7 +195,7 @@ interface RouteConfiguration<TPath extends string, TInputParams extends InputPat
|
|
|
194
195
|
/**
|
|
195
196
|
* [**Documentation**](https://js2me.github.io/mobx-route/core/Route.html#beforeopen)
|
|
196
197
|
*/
|
|
197
|
-
beforeOpen?: (
|
|
198
|
+
beforeOpen?: (navigationTransaction: NavigationTrx<NoInfer<TInputParams>>) => MaybePromise<BeforeOpenFeedback>;
|
|
198
199
|
/**
|
|
199
200
|
* [**Documentation**](https://js2me.github.io/mobx-route/core/Route.html#afterclose)
|
|
200
201
|
*/
|
|
@@ -211,6 +212,7 @@ interface RouteConfiguration<TPath extends string, TInputParams extends InputPat
|
|
|
211
212
|
type AnyRoute = IRoute;
|
|
212
213
|
interface IRoute<TPath extends string = string, TInputParams extends InputPathParams<TPath> = InputPathParams<TPath>, TOutputParams extends AnyObject = ParsedPathParams<TPath>> {
|
|
213
214
|
isOpened: boolean;
|
|
215
|
+
isOpening: boolean;
|
|
214
216
|
path: TPath;
|
|
215
217
|
/**
|
|
216
218
|
* [**Documentation**](https://js2me.github.io/mobx-route/core/Route.html#hasopenedchildren-boolean)
|
|
@@ -288,7 +290,8 @@ declare class Route<TPath extends string, TInputParams extends InputPathParams<T
|
|
|
288
290
|
private _tokenData;
|
|
289
291
|
private _matcher?;
|
|
290
292
|
private _compiler?;
|
|
291
|
-
private
|
|
293
|
+
private skipPathMatchCheck;
|
|
294
|
+
protected status: 'opening' | 'closed' | 'open-rejected' | 'open-confirmed' | 'unknown';
|
|
292
295
|
meta?: AnyObject;
|
|
293
296
|
/**
|
|
294
297
|
* Indicates if this route is an index route. Index routes activate when parent route path matches exactly.
|
|
@@ -306,6 +309,7 @@ declare class Route<TPath extends string, TInputParams extends InputPathParams<T
|
|
|
306
309
|
constructor(path: TPath, config?: RouteConfiguration<TPath, TInputParams, TOutputParams, TParentRoute>);
|
|
307
310
|
protected get baseUrl(): string | undefined;
|
|
308
311
|
protected get parsedPathData(): ParsedPathData<TPath> | null;
|
|
312
|
+
get isOpening(): boolean;
|
|
309
313
|
/**
|
|
310
314
|
* Matched path segment for current URL.
|
|
311
315
|
*
|
|
@@ -318,6 +322,7 @@ declare class Route<TPath extends string, TInputParams extends InputPathParams<T
|
|
|
318
322
|
* [**Documentation**](https://js2me.github.io/mobx-route/core/Route.html#params-parsedpathparams-null)
|
|
319
323
|
*/
|
|
320
324
|
get params(): TOutputParams | null;
|
|
325
|
+
protected get isPathMatched(): boolean;
|
|
321
326
|
/**
|
|
322
327
|
* Defines the "open" state for this route.
|
|
323
328
|
*
|
|
@@ -366,11 +371,11 @@ declare class Route<TPath extends string, TInputParams extends InputPathParams<T
|
|
|
366
371
|
]): Promise<void>;
|
|
367
372
|
open(url: string, navigateParams?: RouteNavigateParams): Promise<void>;
|
|
368
373
|
open(url: string, replace?: RouteNavigateParams['replace'], query?: RouteNavigateParams['query']): Promise<void>;
|
|
369
|
-
protected beforeOpen(openData: PreparedNavigationData<TInputParams>): MaybePromise<BeforeOpenFeedback>;
|
|
370
|
-
protected afterClose(): true | void;
|
|
371
374
|
protected get tokenData(): TokenData;
|
|
372
|
-
|
|
373
|
-
|
|
375
|
+
protected confirmOpening(trx: NavigationTrx<TInputParams>): Promise<boolean | (NavigationTrx<TInputParams> & Pick<NavigationTrx<AnyObject>, "url" | "state" | "replace">)>;
|
|
376
|
+
protected confirmClosing(): boolean;
|
|
377
|
+
private firstPathMatchingRun;
|
|
378
|
+
private checkPathMatch;
|
|
374
379
|
private get isAbleToMergeQuery();
|
|
375
380
|
destroy(): void;
|
|
376
381
|
}
|
|
@@ -418,4 +423,4 @@ declare const createRouter: <TRoutesCollection extends RoutesCollection>(config:
|
|
|
418
423
|
declare const isRouteEntity: (route: any) => route is AnyRouteEntity;
|
|
419
424
|
|
|
420
425
|
export { Route, RouteGroup, Router, VirtualRoute, createRoute, createRouteGroup, createRouter, createVirtualRoute, isRouteEntity, routeConfig };
|
|
421
|
-
export type { AbstractRouteGroup, AbstractVirtualRoute, AnyAbstractRoute, AnyAbstractRouteEntity, AnyRoute, AnyRouteEntity, AnyRouteGroup, AnyRouter, AnyVirtualRoute, BeforeOpenFeedback, CreatedUrlOutputParams, IRoute, InferInputParams, InferParams, InferPath, InputPathParam, InputPathParams, ParsedPathData, ParsedPathParam, ParsedPathParams, PathToObject,
|
|
426
|
+
export type { AbstractRouteGroup, AbstractVirtualRoute, AnyAbstractRoute, AnyAbstractRouteEntity, AnyRoute, AnyRouteEntity, AnyRouteGroup, AnyRouter, AnyVirtualRoute, BeforeOpenFeedback, CreatedUrlOutputParams, IRoute, InferInputParams, InferParams, InferPath, InputPathParam, InputPathParams, NavigationTrx, ParsedPathData, ParsedPathParam, ParsedPathParams, PathToObject, RouteConfiguration, RouteGlobalConfig, RouteNavigateParams, RouteParams, RouterConfiguration, RouterNavigateOptions, RoutesArrayCollection, RoutesCollection, RoutesObjectCollection, UrlCreateParams, UrlCreateParamsFn, VirtualOpenExtraParams, VirtualRouteConfiguration };
|
package/index.js
CHANGED
|
@@ -2,7 +2,7 @@ import { createBrowserHistory, QueryParams, isObservableHistory, buildSearchStri
|
|
|
2
2
|
export * from "mobx-location-history";
|
|
3
3
|
import { createGlobalDynamicConfig } from "yummies/complex";
|
|
4
4
|
import { LinkedAbortController } from "linked-abort-controller";
|
|
5
|
-
import { computed, observable, action, makeObservable,
|
|
5
|
+
import { computed, observable, action, makeObservable, reaction, runInAction, onBecomeObserved, onBecomeUnobserved } from "mobx";
|
|
6
6
|
import { match, compile, parse } from "path-to-regexp";
|
|
7
7
|
import { callFunction } from "yummies/common";
|
|
8
8
|
let localHistory;
|
|
@@ -33,7 +33,8 @@ const routeConfig = createGlobalDynamicConfig(
|
|
|
33
33
|
location,
|
|
34
34
|
queryParams
|
|
35
35
|
};
|
|
36
|
-
}
|
|
36
|
+
},
|
|
37
|
+
Symbol.for("MOBX_ROUTE_CONFIG")
|
|
37
38
|
);
|
|
38
39
|
class Route {
|
|
39
40
|
constructor(path, config = {}) {
|
|
@@ -45,35 +46,28 @@ class Route {
|
|
|
45
46
|
this.isIndex = !!this.config.index;
|
|
46
47
|
this.isHash = !!this.config.hash;
|
|
47
48
|
this.meta = this.config.meta;
|
|
49
|
+
this.status = "unknown";
|
|
48
50
|
this.parent = config.parent ?? null;
|
|
49
|
-
computed
|
|
51
|
+
computed(this, "isPathMatched");
|
|
52
|
+
computed(this, "isOpened");
|
|
50
53
|
computed.struct(this, "data");
|
|
51
54
|
computed.struct(this, "params");
|
|
52
|
-
computed
|
|
53
|
-
computed
|
|
54
|
-
computed
|
|
55
|
+
computed(this, "currentPath");
|
|
56
|
+
computed(this, "hasOpenedChildren");
|
|
57
|
+
computed(this, "isAbleToMergeQuery");
|
|
55
58
|
computed(this, "baseUrl");
|
|
56
59
|
observable(this, "children");
|
|
57
60
|
observable.ref(this, "parent");
|
|
61
|
+
observable.ref(this, "status");
|
|
62
|
+
computed(this, "isOpening");
|
|
58
63
|
action(this, "addChildren");
|
|
64
|
+
action(this, "confirmOpening");
|
|
65
|
+
action(this, "confirmClosing");
|
|
59
66
|
action(this, "removeChildren");
|
|
60
67
|
makeObservable(this);
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
}
|
|
65
|
-
this.reactionDisposer = reaction(
|
|
66
|
-
() => this.isOpened,
|
|
67
|
-
this.processOpenedState,
|
|
68
|
-
{
|
|
69
|
-
signal: this.abortController.signal,
|
|
70
|
-
fireImmediately: true
|
|
71
|
-
}
|
|
72
|
-
);
|
|
73
|
-
});
|
|
74
|
-
onBecomeUnobserved(this, "isOpened", () => {
|
|
75
|
-
this.reactionDisposer?.();
|
|
76
|
-
this.reactionDisposer = void 0;
|
|
68
|
+
reaction(() => this.isPathMatched, this.checkPathMatch, {
|
|
69
|
+
signal: this.abortController.signal,
|
|
70
|
+
fireImmediately: true
|
|
77
71
|
});
|
|
78
72
|
}
|
|
79
73
|
abortController;
|
|
@@ -83,7 +77,8 @@ class Route {
|
|
|
83
77
|
_tokenData;
|
|
84
78
|
_matcher;
|
|
85
79
|
_compiler;
|
|
86
|
-
|
|
80
|
+
skipPathMatchCheck = false;
|
|
81
|
+
status;
|
|
87
82
|
meta;
|
|
88
83
|
/**
|
|
89
84
|
* Indicates if this route is an index route. Index routes activate when parent route path matches exactly.
|
|
@@ -119,7 +114,7 @@ class Route {
|
|
|
119
114
|
return { params: {}, path: pathnameToCheck };
|
|
120
115
|
}
|
|
121
116
|
this._matcher ??= match(this.tokenData, {
|
|
122
|
-
end: false,
|
|
117
|
+
end: this.config.exact ?? false,
|
|
123
118
|
...this.config.matchOptions
|
|
124
119
|
});
|
|
125
120
|
const parsed = this._matcher(pathnameToCheck);
|
|
@@ -128,6 +123,9 @@ class Route {
|
|
|
128
123
|
}
|
|
129
124
|
return parsed;
|
|
130
125
|
}
|
|
126
|
+
get isOpening() {
|
|
127
|
+
return this.status === "opening";
|
|
128
|
+
}
|
|
131
129
|
/**
|
|
132
130
|
* Matched path segment for current URL.
|
|
133
131
|
*
|
|
@@ -159,13 +157,16 @@ class Route {
|
|
|
159
157
|
}
|
|
160
158
|
return params;
|
|
161
159
|
}
|
|
160
|
+
get isPathMatched() {
|
|
161
|
+
return this.parsedPathData !== null;
|
|
162
|
+
}
|
|
162
163
|
/**
|
|
163
164
|
* Defines the "open" state for this route.
|
|
164
165
|
*
|
|
165
166
|
* [**Documentation**](https://js2me.github.io/mobx-route/core/Route.html#isopened-boolean)
|
|
166
167
|
*/
|
|
167
168
|
get isOpened() {
|
|
168
|
-
if (this.params === null || this.
|
|
169
|
+
if (!this.isPathMatched || this.params === null || this.status !== "open-confirmed") {
|
|
169
170
|
return false;
|
|
170
171
|
}
|
|
171
172
|
return !this.config.checkOpened || this.config.checkOpened(this.parsedPathData);
|
|
@@ -222,9 +223,7 @@ class Route {
|
|
|
222
223
|
};
|
|
223
224
|
const urlCreateParams = this.config.createUrl?.(defaultUrlCreateParams, this.query.data) ?? routeConfig.get().createUrl?.(defaultUrlCreateParams, this.query.data) ?? defaultUrlCreateParams;
|
|
224
225
|
const path = this._compiler(this.processParams(urlCreateParams.params));
|
|
225
|
-
const url =
|
|
226
|
-
""
|
|
227
|
-
);
|
|
226
|
+
const url = `${urlCreateParams.baseUrl || ""}${this.isHash ? "#" : ""}${path}`;
|
|
228
227
|
if (outputParams?.omitQuery) {
|
|
229
228
|
return url;
|
|
230
229
|
}
|
|
@@ -253,59 +252,96 @@ class Route {
|
|
|
253
252
|
url = this.createUrl(args[0], query);
|
|
254
253
|
}
|
|
255
254
|
const state = rawState ?? null;
|
|
256
|
-
const
|
|
255
|
+
const trx = {
|
|
257
256
|
url,
|
|
258
257
|
params,
|
|
259
258
|
replace,
|
|
260
259
|
state,
|
|
261
260
|
query
|
|
262
261
|
};
|
|
263
|
-
const
|
|
264
|
-
if (
|
|
262
|
+
const isConfirmed = await this.confirmOpening(trx);
|
|
263
|
+
if (!isConfirmed) {
|
|
265
264
|
return;
|
|
266
265
|
}
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
if (replace) {
|
|
271
|
-
this.history.replace(url, state);
|
|
266
|
+
this.skipPathMatchCheck = true;
|
|
267
|
+
if (trx.replace) {
|
|
268
|
+
this.history.replace(trx.url, trx.state);
|
|
272
269
|
} else {
|
|
273
|
-
this.history.push(url, state);
|
|
270
|
+
this.history.push(trx.url, trx.state);
|
|
274
271
|
}
|
|
275
|
-
|
|
276
|
-
|
|
272
|
+
}
|
|
273
|
+
get tokenData() {
|
|
274
|
+
if (!this._tokenData) {
|
|
275
|
+
this._tokenData = parse(this.path, this.config.parseOptions);
|
|
277
276
|
}
|
|
277
|
+
return this._tokenData;
|
|
278
278
|
}
|
|
279
|
-
|
|
279
|
+
async confirmOpening(trx) {
|
|
280
|
+
this.status = "opening";
|
|
280
281
|
if (this.config.beforeOpen) {
|
|
281
|
-
|
|
282
|
+
const feedback = await this.config.beforeOpen(trx);
|
|
283
|
+
if (feedback === false) {
|
|
284
|
+
runInAction(() => {
|
|
285
|
+
this.status = "open-rejected";
|
|
286
|
+
});
|
|
287
|
+
return false;
|
|
288
|
+
}
|
|
289
|
+
if (typeof feedback === "object") {
|
|
290
|
+
runInAction(() => {
|
|
291
|
+
this.status = "open-confirmed";
|
|
292
|
+
});
|
|
293
|
+
return Object.assign(trx, feedback);
|
|
294
|
+
}
|
|
282
295
|
}
|
|
296
|
+
runInAction(() => {
|
|
297
|
+
this.status = "open-confirmed";
|
|
298
|
+
});
|
|
283
299
|
return true;
|
|
284
300
|
}
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
return this.config.afterClose();
|
|
288
|
-
}
|
|
301
|
+
confirmClosing() {
|
|
302
|
+
this.status = "closed";
|
|
289
303
|
return true;
|
|
290
304
|
}
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
}
|
|
297
|
-
firstOpenedStateCheck = true;
|
|
298
|
-
processOpenedState = (isOpened) => {
|
|
299
|
-
if (this.firstOpenedStateCheck) {
|
|
300
|
-
this.firstOpenedStateCheck = false;
|
|
301
|
-
if (!isOpened) {
|
|
305
|
+
firstPathMatchingRun = true;
|
|
306
|
+
checkPathMatch = async (isPathMathched) => {
|
|
307
|
+
if (this.firstPathMatchingRun) {
|
|
308
|
+
this.firstPathMatchingRun = false;
|
|
309
|
+
if (!isPathMathched) {
|
|
302
310
|
return;
|
|
303
311
|
}
|
|
304
312
|
}
|
|
305
|
-
if (
|
|
313
|
+
if (this.skipPathMatchCheck) {
|
|
314
|
+
this.skipPathMatchCheck = false;
|
|
315
|
+
return;
|
|
316
|
+
}
|
|
317
|
+
if (isPathMathched) {
|
|
318
|
+
const trx = {
|
|
319
|
+
url: this.parsedPathData.path,
|
|
320
|
+
params: this.parsedPathData.params,
|
|
321
|
+
state: this.history.location.state,
|
|
322
|
+
query: this.query.data
|
|
323
|
+
};
|
|
324
|
+
const nextTrxOrConfirmed = await this.confirmOpening(trx);
|
|
325
|
+
if (!nextTrxOrConfirmed) {
|
|
326
|
+
return;
|
|
327
|
+
}
|
|
306
328
|
this.config.afterOpen?.(this.parsedPathData, this);
|
|
329
|
+
if (typeof nextTrxOrConfirmed === "object") {
|
|
330
|
+
if (nextTrxOrConfirmed.replace) {
|
|
331
|
+
this.history.replace(
|
|
332
|
+
nextTrxOrConfirmed.url,
|
|
333
|
+
nextTrxOrConfirmed.state
|
|
334
|
+
);
|
|
335
|
+
} else {
|
|
336
|
+
this.history.push(nextTrxOrConfirmed.url, nextTrxOrConfirmed.state);
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
return;
|
|
307
340
|
} else {
|
|
308
|
-
this.
|
|
341
|
+
const isConfirmed = this.confirmClosing();
|
|
342
|
+
if (isConfirmed) {
|
|
343
|
+
this.config.afterClose?.();
|
|
344
|
+
}
|
|
309
345
|
}
|
|
310
346
|
};
|
|
311
347
|
get isAbleToMergeQuery() {
|
package/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sources":["../src/core/config/config.ts","../src/core/route/route.ts","../src/core/route-group/route-group.ts","../src/core/router/router.ts","../src/core/utils/is-route-entity.ts","../src/core/virtual-route/virtual-route.ts"],"sourcesContent":["import {\n createBrowserHistory,\n type History,\n type IQueryParams,\n isObservableHistory,\n QueryParams,\n} from 'mobx-location-history';\nimport { createGlobalDynamicConfig } from 'yummies/complex';\n\nimport type { RouteGlobalConfig } from './config.types.js';\n\nlet localHistory: History | undefined;\n\nexport const routeConfig = createGlobalDynamicConfig<RouteGlobalConfig>(\n (update) => {\n if (localHistory && update?.history && isObservableHistory(localHistory)) {\n localHistory.destroy();\n }\n\n let history: History;\n\n if (update?.history) {\n history = update.history;\n } else {\n history = localHistory = createBrowserHistory();\n }\n\n let queryParams: IQueryParams;\n\n if (update?.history && !update.queryParams) {\n queryParams = new QueryParams({ history });\n } else {\n if (update?.queryParams) {\n queryParams = update.queryParams;\n } else {\n queryParams = new QueryParams({ history });\n }\n }\n\n return {\n ...update,\n history,\n location,\n queryParams,\n };\n },\n);\n","import { LinkedAbortController } from 'linked-abort-controller';\nimport {\n action,\n computed,\n makeObservable,\n observable,\n onBecomeObserved,\n onBecomeUnobserved,\n reaction,\n} from 'mobx';\nimport {\n buildSearchString,\n type History,\n type IQueryParams,\n} from 'mobx-location-history';\nimport {\n compile,\n match,\n type ParamData,\n parse,\n type TokenData,\n} from 'path-to-regexp';\nimport type { AnyObject, IsPartial, Maybe, MaybePromise } from 'yummies/types';\n\nimport { routeConfig } from '../config/index.js';\n\nimport type {\n AnyRoute,\n BeforeOpenFeedback,\n CreatedUrlOutputParams,\n InputPathParams,\n IRoute,\n ParsedPathData,\n ParsedPathParams,\n PreparedNavigationData,\n RouteConfiguration,\n RouteNavigateParams,\n UrlCreateParams,\n} from './route.types.js';\n\n/**\n * Class for creating path based route.\n *\n * [**Documentation**](https://js2me.github.io/mobx-route/core/Route.html)\n */\nexport class Route<\n TPath extends string,\n TInputParams extends InputPathParams<TPath> = InputPathParams<TPath>,\n TOutputParams extends AnyObject = ParsedPathParams<TPath>,\n TParentRoute extends Route<any, any, any, any> | null = null,\n> implements IRoute<TPath, TInputParams, TOutputParams>\n{\n protected abortController: AbortController;\n protected history: History;\n parent: TParentRoute;\n\n query: IQueryParams;\n\n private _tokenData: TokenData | undefined;\n private _matcher?: ReturnType<typeof match>;\n private _compiler?: ReturnType<typeof compile>;\n private reactionDisposer: Maybe<VoidFunction>;\n\n meta?: AnyObject;\n\n /**\n * Indicates if this route is an index route. Index routes activate when parent route path matches exactly.\n *\n * [**Documentation**](https://js2me.github.io/mobx-route/core/Route.html#isindex-boolean)\n */\n isIndex: boolean;\n\n /**\n * Indicates if this route is an hash route.\n *\n * [**Documentation**](https://js2me.github.io/mobx-route/core/Route.html#ishash-boolean)\n */\n isHash: boolean;\n\n children: AnyRoute[] = [];\n\n constructor(\n public path: TPath,\n protected config: RouteConfiguration<\n TPath,\n TInputParams,\n TOutputParams,\n TParentRoute\n > = {},\n ) {\n this.abortController = new LinkedAbortController(config.abortSignal);\n this.history = config.history ?? routeConfig.get().history;\n this.query = config.queryParams ?? routeConfig.get().queryParams;\n this.isIndex = !!this.config.index;\n this.isHash = !!this.config.hash;\n this.meta = this.config.meta;\n this.parent = config.parent ?? (null as unknown as TParentRoute);\n\n computed.struct(this, 'isOpened');\n computed.struct(this, 'data');\n computed.struct(this, 'params');\n computed.struct(this, 'currentPath');\n computed.struct(this, 'hasOpenedChildren');\n computed.struct(this, 'isAbleToMergeQuery');\n computed(this, 'baseUrl');\n\n observable(this, 'children');\n observable.ref(this, 'parent');\n action(this, 'addChildren');\n action(this, 'removeChildren');\n\n makeObservable(this);\n\n onBecomeObserved(this, 'isOpened', () => {\n if (!config.afterOpen && !config.afterClose) {\n return;\n }\n\n this.reactionDisposer = reaction(\n () => this.isOpened,\n this.processOpenedState,\n {\n signal: this.abortController.signal,\n fireImmediately: true,\n },\n );\n });\n onBecomeUnobserved(this, 'isOpened', () => {\n this.reactionDisposer?.();\n this.reactionDisposer = undefined;\n });\n }\n\n protected get baseUrl() {\n const baseUrl = this.config.baseUrl ?? routeConfig.get().baseUrl;\n return baseUrl?.endsWith('/') ? baseUrl.slice(0, -1) : baseUrl;\n }\n\n protected get parsedPathData(): ParsedPathData<TPath> | null {\n let pathnameToCheck: string;\n\n if (this.isHash) {\n pathnameToCheck = this.history.location.hash.slice(1);\n } else {\n pathnameToCheck = this.history.location.pathname;\n }\n\n if (this.baseUrl) {\n if (!this.history.location.pathname.startsWith(this.baseUrl)) {\n return null;\n }\n\n pathnameToCheck = pathnameToCheck.replace(this.baseUrl, '');\n }\n\n if (\n (this.path === '' || this.path === '/') &&\n (pathnameToCheck === '/' || pathnameToCheck === '')\n ) {\n return { params: {} as any, path: pathnameToCheck };\n }\n\n this._matcher ??= match(this.tokenData, {\n end: false,\n ...this.config.matchOptions,\n });\n const parsed = this._matcher(pathnameToCheck);\n\n if (parsed === false) {\n return null;\n }\n\n return parsed as ParsedPathData<TPath>;\n }\n\n /**\n * Matched path segment for current URL.\n *\n * [**Documentation**](https://js2me.github.io/mobx-route/core/Route.html#currentpath-parsedpathname-null)\n */\n get currentPath(): string | null {\n return this.parsedPathData?.path ?? null;\n }\n\n /**\n * Current parsed path parameters.\n *\n * [**Documentation**](https://js2me.github.io/mobx-route/core/Route.html#params-parsedpathparams-null)\n */\n get params(): TOutputParams | null {\n if (!this.parsedPathData?.params) {\n return null;\n }\n\n let params: TOutputParams | null =\n (this.parsedPathData?.params as unknown as Maybe<TOutputParams>) ?? null;\n\n if (this.config.params) {\n const result = this.config.params(\n this.parsedPathData.params,\n this.config.meta,\n );\n if (result) {\n params = result;\n } else {\n return null;\n }\n }\n\n return params;\n }\n\n /**\n * Defines the \"open\" state for this route.\n *\n * [**Documentation**](https://js2me.github.io/mobx-route/core/Route.html#isopened-boolean)\n */\n get isOpened() {\n if (this.params === null || this.parsedPathData === null) {\n return false;\n }\n\n return (\n !this.config.checkOpened || this.config.checkOpened(this.parsedPathData)\n );\n }\n\n /**\n * Allows to create child route based on this route with merging this route path and extending path.\n *\n * [**Documentation**](https://js2me.github.io/mobx-route/core/Route.html#extend-path-config-route)\n */\n extend<\n TExtendedPath extends string,\n TExtendedInputParams extends\n InputPathParams<`${TPath}${TExtendedPath}`> = InputPathParams<`${TPath}${TExtendedPath}`>,\n TExtendedOutputParams extends AnyObject = TInputParams &\n ParsedPathParams<`${TPath}${TExtendedPath}`>,\n >(\n path: TExtendedPath,\n config?: Omit<\n RouteConfiguration<\n `${TPath}${TExtendedPath}`,\n TInputParams & TExtendedInputParams,\n TExtendedOutputParams,\n any\n >,\n 'parent'\n >,\n ) {\n type ExtendedRoutePath = `${TPath}${TExtendedPath}`;\n type ParentRoute = this;\n // biome-ignore lint/correctness/noUnusedVariables: this is need to extract unused fields\n const { index, params, ...configFromCurrentRoute } = this.config;\n\n const extendedChild = new Route<\n ExtendedRoutePath,\n TInputParams & TExtendedInputParams,\n TExtendedOutputParams,\n ParentRoute\n >(`${this.path}${path}`, {\n ...configFromCurrentRoute,\n ...config,\n parent: this,\n } as any);\n\n this.addChildren(extendedChild as any);\n\n return extendedChild;\n }\n\n addChildren(...routes: AnyRoute[]) {\n this.children.push(...routes);\n }\n\n removeChildren(...routes: AnyRoute[]) {\n this.children = this.children.filter((child) => !routes.includes(child));\n }\n\n /**\n * [**Documentation**](https://js2me.github.io/mobx-route/core/Route.html#hasopenedchildren-boolean)\n */\n get hasOpenedChildren(): boolean {\n return this.children.some(\n (child) => child.isOpened || child.hasOpenedChildren,\n );\n }\n\n protected processParams(\n params?: TInputParams | null | undefined,\n ): ParamData | undefined {\n if (params == null) return undefined;\n\n return Object.entries(params).reduce((acc, [key, value]) => {\n if (value != null) {\n acc[key] = Array.isArray(value) ? value.map(String) : String(value);\n }\n return acc;\n }, {} as ParamData);\n }\n\n createUrl(\n ...args: IsPartial<TInputParams> extends true\n ? [\n params?: Maybe<TInputParams>,\n query?: Maybe<AnyObject>,\n mergeQueryOrParams?: boolean | CreatedUrlOutputParams,\n ]\n : [\n params: TInputParams,\n query?: Maybe<AnyObject>,\n mergeQueryOrParams?: boolean | CreatedUrlOutputParams,\n ]\n ) {\n const params = args[0];\n const rawQuery = args[1];\n const mergeQueryOrOutputParams = args[2] ?? this.isAbleToMergeQuery;\n const outputParams: Maybe<CreatedUrlOutputParams> =\n typeof mergeQueryOrOutputParams === 'boolean'\n ? { mergeQuery: mergeQueryOrOutputParams }\n : mergeQueryOrOutputParams;\n\n const query = outputParams?.mergeQuery\n ? { ...this.query.data, ...rawQuery }\n : (rawQuery ?? {});\n\n this._compiler ??= compile(this.tokenData);\n\n const defaultUrlCreateParams: UrlCreateParams<TInputParams> = {\n baseUrl: this.baseUrl,\n params: params as TInputParams,\n query,\n };\n const urlCreateParams: UrlCreateParams<TInputParams> =\n this.config.createUrl?.(defaultUrlCreateParams, this.query.data) ??\n routeConfig.get().createUrl?.(defaultUrlCreateParams, this.query.data) ??\n defaultUrlCreateParams;\n\n const path = this._compiler(this.processParams(urlCreateParams.params));\n\n const url = [urlCreateParams.baseUrl, this.isHash ? '#' : '', path].join(\n '',\n );\n\n if (outputParams?.omitQuery) {\n return url;\n }\n\n return `${url}${buildSearchString(urlCreateParams.query)}`;\n }\n\n /**\n * Navigates to this route.\n *\n * [**Documentation**](https://js2me.github.io/mobx-route/core/Route.html#open-args)\n */\n open(\n ...args: IsPartial<TInputParams> extends true\n ? [\n params?: TInputParams | null | undefined,\n navigateParams?: RouteNavigateParams,\n ]\n : [params: TInputParams, navigateParams?: RouteNavigateParams]\n ): Promise<void>;\n open(\n ...args: IsPartial<TInputParams> extends true\n ? [\n params?: TInputParams | null | undefined,\n replace?: RouteNavigateParams['replace'],\n query?: RouteNavigateParams['query'],\n ]\n : [\n params: TInputParams,\n replace?: RouteNavigateParams['replace'],\n query?: RouteNavigateParams['query'],\n ]\n ): Promise<void>;\n open(url: string, navigateParams?: RouteNavigateParams): Promise<void>;\n open(\n url: string,\n replace?: RouteNavigateParams['replace'],\n query?: RouteNavigateParams['query'],\n ): Promise<void>;\n\n /**\n * Navigates to this route.\n *\n * [**Documentation**](https://js2me.github.io/mobx-route/core/Route.html#open-args)\n */\n async open(...args: any[]) {\n const {\n replace,\n state: rawState,\n query: rawQuery,\n mergeQuery: rawMergeQuery,\n } = typeof args[1] === 'boolean' || args.length > 2\n ? ({ replace: args[1], query: args[2] } as RouteNavigateParams)\n : ((args[1] ?? {}) as RouteNavigateParams);\n let url: string;\n let params: Maybe<InputPathParams<TPath>>;\n\n const mergeQuery = rawMergeQuery ?? this.isAbleToMergeQuery;\n const query = mergeQuery ? { ...this.query.data, ...rawQuery } : rawQuery;\n\n if (typeof args[0] === 'string') {\n url = args[0];\n } else {\n params = args[0] as InputPathParams<TPath>;\n url = this.createUrl(args[0], query);\n }\n\n const state = rawState ?? null;\n\n const navigationData: PreparedNavigationData<TInputParams> = {\n url,\n params: params as TInputParams,\n replace,\n state,\n query,\n };\n\n const feedback = await this.beforeOpen(navigationData);\n\n if (feedback === false) {\n return;\n }\n\n if (typeof feedback === 'object') {\n Object.assign(navigationData, feedback);\n }\n\n if (replace) {\n this.history.replace(url, state);\n } else {\n this.history.push(url, state);\n }\n\n if (!this.reactionDisposer && this.isOpened) {\n this.config.afterOpen?.(this.parsedPathData!, this);\n }\n }\n\n protected beforeOpen(\n openData: PreparedNavigationData<TInputParams>,\n ): MaybePromise<BeforeOpenFeedback> {\n if (this.config.beforeOpen) {\n return this.config.beforeOpen(openData);\n }\n\n return true;\n }\n\n protected afterClose() {\n if (this.config.afterClose) {\n return this.config.afterClose();\n }\n\n return true;\n }\n\n protected get tokenData() {\n if (!this._tokenData) {\n this._tokenData = parse(this.path, this.config.parseOptions);\n }\n return this._tokenData;\n }\n\n private firstOpenedStateCheck = true;\n private processOpenedState = (isOpened: boolean) => {\n if (this.firstOpenedStateCheck) {\n this.firstOpenedStateCheck = false;\n // ignore first 'afterClose' callback call\n if (!isOpened) {\n return;\n }\n }\n\n if (isOpened) {\n this.config.afterOpen?.(this.parsedPathData!, this);\n } else {\n this.config.afterClose?.();\n }\n };\n\n private get isAbleToMergeQuery() {\n return this.config.mergeQuery ?? routeConfig.get().mergeQuery;\n }\n\n destroy() {\n this.abortController.abort();\n }\n}\n\nexport const createRoute = <\n TPath extends string,\n TInputParams extends InputPathParams<TPath> = InputPathParams<TPath>,\n TOutputParams extends AnyObject = ParsedPathParams<TPath>,\n TParentRoute extends Route<any, any, any, any> | null = null,\n>(\n path: TPath,\n config?: RouteConfiguration<TPath, TInputParams, TOutputParams, TParentRoute>,\n) => new Route<TPath, TInputParams, TOutputParams, TParentRoute>(path, config);\n","import { computed, makeObservable, observable } from 'mobx';\n\nimport type {\n AbstractRouteGroup,\n AnyRouteEntity,\n RoutesCollection,\n} from './route-group.types.js';\n\ndeclare const process: { env: { NODE_ENV?: string } };\n\n/**\n * Class for grouping related routes and managing their state.\n *\n * [**Documentation**](https://js2me.github.io/mobx-route/core/RouteGroup.html)\n */\nexport class RouteGroup<TRoutesCollection extends RoutesCollection>\n implements AbstractRouteGroup<TRoutesCollection>\n{\n routes: TRoutesCollection;\n\n constructor(\n routes: TRoutesCollection,\n private _indexRoute?: AnyRouteEntity,\n ) {\n this.routes = routes;\n\n computed.struct(this, 'isOpened');\n computed.struct(this, 'indexRoute');\n observable.shallow(this, 'routes');\n makeObservable(this);\n }\n\n /**\n * Returns true if at least one route in the group is open.\n *\n * [**Documentation**](https://js2me.github.io/mobx-route/core/RouteGroup.html#isopened-boolean)\n */\n get isOpened(): boolean {\n const routes = Object.values(this.routes);\n return routes.some(\n (route) =>\n route.isOpened ||\n ('hasOpenedChildren' in route && route.hasOpenedChildren),\n );\n }\n\n /**\n * First found index route.\n *\n * [**Documentation**](https://js2me.github.io/mobx-route/core/RouteGroup.html#indexroute-route-undefined)\n */\n get indexRoute(): AnyRouteEntity | undefined {\n return (this._indexRoute ??\n Object.values(this.routes).find(\n (route) => 'isIndex' in route && route.isIndex,\n )) as unknown as AnyRouteEntity;\n }\n\n /**\n * Main navigation method for the group.\n *\n * [**Documentation**](https://js2me.github.io/mobx-route/core/RouteGroup.html#open-args-any-void)\n */\n open(...args: any[]) {\n let lastGroupRoute: RouteGroup<any> | undefined;\n\n if (this.indexRoute && 'open' in this.indexRoute) {\n this.indexRoute.open(...args);\n return;\n }\n\n for (const routeName in this.routes) {\n const route = this.routes[routeName];\n if (route instanceof RouteGroup) {\n lastGroupRoute = route;\n }\n }\n\n if (lastGroupRoute) {\n lastGroupRoute.open(...args);\n } else if (process.env.NODE_ENV !== 'production') {\n console.warn(\n \"RouteGroup doesn't have index route. open() method doesn't work.\",\n );\n }\n }\n}\n\nexport const createRouteGroup = <TRoutesCollection extends RoutesCollection>(\n routes: TRoutesCollection,\n indexRoute?: AnyRouteEntity,\n) => new RouteGroup<TRoutesCollection>(routes, indexRoute);\n","import { computed, makeObservable } from 'mobx';\nimport {\n buildSearchString,\n type History,\n type IQueryParams,\n} from 'mobx-location-history';\n\nimport { routeConfig } from '../config/index.js';\nimport type { RoutesCollection } from '../route-group/index.js';\n\nimport type {\n RouterConfiguration,\n RouterNavigateOptions,\n} from './router.types.js';\n\n/**\n * Class for centralized routing management.\n *\n * [**Documentation**](https://js2me.github.io/mobx-route/core/Router.html)\n */\nexport class Router<TRoutesCollection extends RoutesCollection> {\n routes: TRoutesCollection;\n history: History;\n query: IQueryParams;\n\n constructor(config: RouterConfiguration<TRoutesCollection>) {\n this.routes = config.routes;\n this.history = config.history ?? routeConfig.get().history;\n this.query = config.queryParams ?? routeConfig.get().queryParams;\n\n computed.struct(this, 'location');\n\n makeObservable(this);\n }\n\n get location() {\n return this.history.location;\n }\n\n navigate(url: string, options?: RouterNavigateOptions) {\n const query =\n (options?.mergeQuery ?? routeConfig.get().mergeQuery)\n ? { ...this.query.data, ...options?.query }\n : { ...options?.query };\n\n const searchString = buildSearchString(query);\n const navigationUrl = `${url}${searchString}`;\n\n if (options?.replace) {\n this.history.replace(navigationUrl, options?.state);\n } else {\n this.history.push(navigationUrl, options?.state);\n }\n }\n}\n\nexport const createRouter = <TRoutesCollection extends RoutesCollection>(\n config: RouterConfiguration<TRoutesCollection>,\n) => new Router(config);\n","import type { AnyRouteEntity } from '../route-group/index.js';\n\nexport const isRouteEntity = (route: any): route is AnyRouteEntity =>\n route && 'isOpened' in route;\n","import { LinkedAbortController } from 'linked-abort-controller';\nimport {\n action,\n computed,\n makeObservable,\n observable,\n onBecomeObserved,\n onBecomeUnobserved,\n reaction,\n runInAction,\n} from 'mobx';\nimport type { IQueryParams } from 'mobx-location-history';\nimport { callFunction } from 'yummies/common';\nimport type { AnyObject, EmptyObject, IsPartial, Maybe } from 'yummies/types';\n\nimport { routeConfig } from '../config/index.js';\n\nimport type {\n AbstractVirtualRoute,\n VirtualOpenExtraParams,\n VirtualRouteConfiguration,\n} from './virtual-route.types.js';\n\n/**\n * Class for creating routes with custom activation logic\n *\n * [**Documentation**](https://js2me.github.io/mobx-route/core/VirtualRoute.html)\n */\nexport class VirtualRoute<TParams extends AnyObject | EmptyObject = EmptyObject>\n implements AbstractVirtualRoute<TParams>\n{\n protected abortController: AbortController;\n query: IQueryParams;\n params: TParams | null;\n\n private isLocalOpened: boolean;\n\n private openChecker: Maybe<VirtualRouteConfiguration<TParams>['checkOpened']>;\n private reactionDisposer: Maybe<VoidFunction>;\n\n constructor(protected config: VirtualRouteConfiguration<TParams> = {}) {\n this.abortController = new LinkedAbortController(config.abortSignal);\n this.query = config.queryParams ?? routeConfig.get().queryParams;\n this.params = callFunction(config.initialParams, this) ?? null;\n this.openChecker = config.checkOpened;\n this.isLocalOpened = this.openChecker?.(this) ?? false;\n\n observable(this, 'params');\n observable.ref(this, 'isLocalOpened');\n observable.ref(this, '_isOpened');\n computed.struct(this, 'isOpened');\n action(this, 'setOpenChecker');\n action(this, 'open');\n action(this, 'close');\n makeObservable(this);\n\n onBecomeObserved(this, 'isOpened', () => {\n if (!config.afterOpen && !config.afterClose) {\n return;\n }\n\n this.reactionDisposer = reaction(\n () => this.isOpened,\n this.processOpenedState,\n {\n signal: this.abortController.signal,\n fireImmediately: true,\n },\n );\n });\n onBecomeUnobserved(this, 'isOpened', () => {\n this.reactionDisposer?.();\n this.reactionDisposer = undefined;\n });\n }\n\n /**\n * [**Documentation**](https://js2me.github.io/mobx-route/core/VirtualRoute.html#isopened-boolean)\n */\n get isOpened() {\n const isOuterOpened = this.openChecker == null || this.openChecker(this);\n return this.isLocalOpened && isOuterOpened;\n }\n\n /**\n * [**Documentation**](https://js2me.github.io/mobx-route/core/VirtualRoute.html#setopenchecker-openchecker-void)\n */\n setOpenChecker(\n openChecker: Maybe<VirtualRouteConfiguration<TParams>['checkOpened']>,\n ) {\n this.openChecker = openChecker;\n }\n\n /**\n * [**Documentation**](https://js2me.github.io/mobx-route/core/VirtualRoute.html#open-params-extraparams-query-replace-promise-void)\n */\n open(\n ...args: IsPartial<TParams> extends true\n ? [params?: Maybe<TParams>, extraParams?: VirtualOpenExtraParams]\n : [params: TParams, extraParams?: VirtualOpenExtraParams]\n ): Promise<void>;\n async open(...args: any[]) {\n const params = (args[0] ?? {}) as unknown as TParams;\n const extraParams: Maybe<VirtualOpenExtraParams> = args[1];\n\n if (this.config.beforeOpen) {\n const beforeOpenResult = await this.config.beforeOpen(params, this);\n if (beforeOpenResult === false) {\n return;\n }\n }\n\n if (this.config.open == null) {\n runInAction(() => {\n this.isLocalOpened = true;\n });\n } else {\n const result = await this.config.open(params, this);\n // because result can return void so this is truthy for opening state\n runInAction(() => {\n this.isLocalOpened = result !== false;\n });\n }\n\n if (!this.isLocalOpened) {\n return;\n }\n\n if (extraParams?.query) {\n this.query.update(extraParams.query, extraParams.replace);\n }\n\n runInAction(() => {\n this.params = params;\n });\n\n if (!this.reactionDisposer && this.isOpened) {\n this.config.afterOpen?.(this.params!, this);\n }\n }\n\n /**\n * [**Documentation**](https://js2me.github.io/mobx-route/core/VirtualRoute.html#close-void)\n */\n close() {\n if (this.config.close == null) {\n this.isLocalOpened = false;\n } else {\n const result = this.config.close(this);\n // because result can return void so this is truthy for opening state\n this.isLocalOpened = result !== false;\n }\n\n this.params = null;\n }\n\n private firstOpenedStateCheck = true;\n private processOpenedState = (isOpened: boolean) => {\n if (this.firstOpenedStateCheck) {\n this.firstOpenedStateCheck = false;\n // ignore first 'afterClose' callback call\n if (!isOpened) {\n return;\n }\n }\n\n if (isOpened) {\n this.config.afterOpen?.(this.params!, this);\n } else {\n this.config.afterClose?.();\n }\n };\n\n destroy() {\n this.abortController.abort();\n }\n}\n\nexport const createVirtualRoute = <\n TParams extends AnyObject | EmptyObject = EmptyObject,\n>(\n config?: VirtualRouteConfiguration<TParams>,\n) => new VirtualRoute<TParams>(config);\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../src/core/config/config.ts","../src/core/route/route.ts","../src/core/route-group/route-group.ts","../src/core/router/router.ts","../src/core/utils/is-route-entity.ts","../src/core/virtual-route/virtual-route.ts"],"sourcesContent":["import {\n createBrowserHistory,\n type History,\n type IQueryParams,\n isObservableHistory,\n QueryParams,\n} from 'mobx-location-history';\nimport { createGlobalDynamicConfig } from 'yummies/complex';\n\nimport type { RouteGlobalConfig } from './config.types.js';\n\nlet localHistory: History | undefined;\n\nexport const routeConfig = createGlobalDynamicConfig<RouteGlobalConfig>(\n (update) => {\n if (localHistory && update?.history && isObservableHistory(localHistory)) {\n localHistory.destroy();\n }\n\n let history: History;\n\n if (update?.history) {\n history = update.history;\n } else {\n history = localHistory = createBrowserHistory();\n }\n\n let queryParams: IQueryParams;\n\n if (update?.history && !update.queryParams) {\n queryParams = new QueryParams({ history });\n } else {\n if (update?.queryParams) {\n queryParams = update.queryParams;\n } else {\n queryParams = new QueryParams({ history });\n }\n }\n\n return {\n ...update,\n history,\n location,\n queryParams,\n };\n },\n Symbol.for('MOBX_ROUTE_CONFIG'),\n);\n","import { LinkedAbortController } from 'linked-abort-controller';\nimport {\n action,\n computed,\n makeObservable,\n observable,\n reaction,\n runInAction,\n} from 'mobx';\nimport {\n buildSearchString,\n type History,\n type IQueryParams,\n} from 'mobx-location-history';\nimport {\n compile,\n match,\n type ParamData,\n parse,\n type TokenData,\n} from 'path-to-regexp';\nimport type { AnyObject, IsPartial, Maybe } from 'yummies/types';\nimport { routeConfig } from '../config/index.js';\nimport type {\n AnyRoute,\n CreatedUrlOutputParams,\n InputPathParams,\n IRoute,\n NavigationTrx,\n ParsedPathData,\n ParsedPathParams,\n RouteConfiguration,\n RouteNavigateParams,\n UrlCreateParams,\n} from './route.types.js';\n\n/**\n * Class for creating path based route.\n *\n * [**Documentation**](https://js2me.github.io/mobx-route/core/Route.html)\n */\nexport class Route<\n TPath extends string,\n TInputParams extends InputPathParams<TPath> = InputPathParams<TPath>,\n TOutputParams extends AnyObject = ParsedPathParams<TPath>,\n TParentRoute extends Route<any, any, any, any> | null = null,\n> implements IRoute<TPath, TInputParams, TOutputParams>\n{\n protected abortController: AbortController;\n protected history: History;\n parent: TParentRoute;\n\n query: IQueryParams;\n\n private _tokenData: TokenData | undefined;\n private _matcher?: ReturnType<typeof match>;\n private _compiler?: ReturnType<typeof compile>;\n private skipPathMatchCheck = false;\n\n protected status:\n | 'opening'\n | 'closed'\n | 'open-rejected'\n | 'open-confirmed'\n | 'unknown';\n\n meta?: AnyObject;\n\n /**\n * Indicates if this route is an index route. Index routes activate when parent route path matches exactly.\n *\n * [**Documentation**](https://js2me.github.io/mobx-route/core/Route.html#isindex-boolean)\n */\n isIndex: boolean;\n\n /**\n * Indicates if this route is an hash route.\n *\n * [**Documentation**](https://js2me.github.io/mobx-route/core/Route.html#ishash-boolean)\n */\n isHash: boolean;\n\n children: AnyRoute[] = [];\n\n constructor(\n public path: TPath,\n protected config: RouteConfiguration<\n TPath,\n TInputParams,\n TOutputParams,\n TParentRoute\n > = {},\n ) {\n this.abortController = new LinkedAbortController(config.abortSignal);\n this.history = config.history ?? routeConfig.get().history;\n this.query = config.queryParams ?? routeConfig.get().queryParams;\n this.isIndex = !!this.config.index;\n this.isHash = !!this.config.hash;\n this.meta = this.config.meta;\n this.status = 'unknown';\n this.parent = config.parent ?? (null as unknown as TParentRoute);\n\n computed(this, 'isPathMatched');\n computed(this, 'isOpened');\n computed.struct(this, 'data');\n computed.struct(this, 'params');\n computed(this, 'currentPath');\n computed(this, 'hasOpenedChildren');\n computed(this, 'isAbleToMergeQuery');\n computed(this, 'baseUrl');\n\n observable(this, 'children');\n observable.ref(this, 'parent');\n observable.ref(this, 'status');\n computed(this, 'isOpening');\n action(this, 'addChildren');\n action(this, 'confirmOpening');\n action(this, 'confirmClosing');\n action(this, 'removeChildren');\n\n makeObservable(this);\n\n reaction(() => this.isPathMatched, this.checkPathMatch, {\n signal: this.abortController.signal,\n fireImmediately: true,\n });\n }\n\n protected get baseUrl() {\n const baseUrl = this.config.baseUrl ?? routeConfig.get().baseUrl;\n return baseUrl?.endsWith('/') ? baseUrl.slice(0, -1) : baseUrl;\n }\n\n protected get parsedPathData(): ParsedPathData<TPath> | null {\n let pathnameToCheck: string;\n\n if (this.isHash) {\n pathnameToCheck = this.history.location.hash.slice(1);\n } else {\n pathnameToCheck = this.history.location.pathname;\n }\n\n if (this.baseUrl) {\n if (!this.history.location.pathname.startsWith(this.baseUrl)) {\n return null;\n }\n\n pathnameToCheck = pathnameToCheck.replace(this.baseUrl, '');\n }\n\n if (\n (this.path === '' || this.path === '/') &&\n (pathnameToCheck === '/' || pathnameToCheck === '')\n ) {\n return { params: {} as any, path: pathnameToCheck };\n }\n\n this._matcher ??= match(this.tokenData, {\n end: this.config.exact ?? false,\n ...this.config.matchOptions,\n });\n const parsed = this._matcher(pathnameToCheck);\n\n if (parsed === false) {\n return null;\n }\n\n return parsed as ParsedPathData<TPath>;\n }\n\n get isOpening() {\n return this.status === 'opening';\n }\n\n /**\n * Matched path segment for current URL.\n *\n * [**Documentation**](https://js2me.github.io/mobx-route/core/Route.html#currentpath-parsedpathname-null)\n */\n get currentPath(): string | null {\n return this.parsedPathData?.path ?? null;\n }\n\n /**\n * Current parsed path parameters.\n *\n * [**Documentation**](https://js2me.github.io/mobx-route/core/Route.html#params-parsedpathparams-null)\n */\n get params(): TOutputParams | null {\n if (!this.parsedPathData?.params) {\n return null;\n }\n\n let params: TOutputParams | null =\n (this.parsedPathData?.params as unknown as Maybe<TOutputParams>) ?? null;\n\n if (this.config.params) {\n const result = this.config.params(\n this.parsedPathData.params,\n this.config.meta,\n );\n if (result) {\n params = result;\n } else {\n return null;\n }\n }\n\n return params;\n }\n\n protected get isPathMatched() {\n return this.parsedPathData !== null;\n }\n\n /**\n * Defines the \"open\" state for this route.\n *\n * [**Documentation**](https://js2me.github.io/mobx-route/core/Route.html#isopened-boolean)\n */\n get isOpened() {\n if (\n !this.isPathMatched ||\n this.params === null ||\n this.status !== 'open-confirmed'\n ) {\n return false;\n }\n\n return (\n !this.config.checkOpened || this.config.checkOpened(this.parsedPathData!)\n );\n }\n\n /**\n * Allows to create child route based on this route with merging this route path and extending path.\n *\n * [**Documentation**](https://js2me.github.io/mobx-route/core/Route.html#extend-path-config-route)\n */\n extend<\n TExtendedPath extends string,\n TExtendedInputParams extends\n InputPathParams<`${TPath}${TExtendedPath}`> = InputPathParams<`${TPath}${TExtendedPath}`>,\n TExtendedOutputParams extends AnyObject = TInputParams &\n ParsedPathParams<`${TPath}${TExtendedPath}`>,\n >(\n path: TExtendedPath,\n config?: Omit<\n RouteConfiguration<\n `${TPath}${TExtendedPath}`,\n TInputParams & TExtendedInputParams,\n TExtendedOutputParams,\n any\n >,\n 'parent'\n >,\n ) {\n type ExtendedRoutePath = `${TPath}${TExtendedPath}`;\n type ParentRoute = this;\n // biome-ignore lint/correctness/noUnusedVariables: this is need to extract unused fields\n const { index, params, ...configFromCurrentRoute } = this.config;\n\n const extendedChild = new Route<\n ExtendedRoutePath,\n TInputParams & TExtendedInputParams,\n TExtendedOutputParams,\n ParentRoute\n >(`${this.path}${path}`, {\n ...configFromCurrentRoute,\n ...config,\n parent: this,\n } as any);\n\n this.addChildren(extendedChild as any);\n\n return extendedChild;\n }\n\n addChildren(...routes: AnyRoute[]) {\n this.children.push(...routes);\n }\n\n removeChildren(...routes: AnyRoute[]) {\n this.children = this.children.filter((child) => !routes.includes(child));\n }\n\n /**\n * [**Documentation**](https://js2me.github.io/mobx-route/core/Route.html#hasopenedchildren-boolean)\n */\n get hasOpenedChildren(): boolean {\n return this.children.some(\n (child) => child.isOpened || child.hasOpenedChildren,\n );\n }\n\n protected processParams(\n params?: TInputParams | null | undefined,\n ): ParamData | undefined {\n if (params == null) return undefined;\n\n return Object.entries(params).reduce((acc, [key, value]) => {\n if (value != null) {\n acc[key] = Array.isArray(value) ? value.map(String) : String(value);\n }\n return acc;\n }, {} as ParamData);\n }\n\n createUrl(\n ...args: IsPartial<TInputParams> extends true\n ? [\n params?: Maybe<TInputParams>,\n query?: Maybe<AnyObject>,\n mergeQueryOrParams?: boolean | CreatedUrlOutputParams,\n ]\n : [\n params: TInputParams,\n query?: Maybe<AnyObject>,\n mergeQueryOrParams?: boolean | CreatedUrlOutputParams,\n ]\n ) {\n const params = args[0];\n const rawQuery = args[1];\n const mergeQueryOrOutputParams = args[2] ?? this.isAbleToMergeQuery;\n const outputParams: Maybe<CreatedUrlOutputParams> =\n typeof mergeQueryOrOutputParams === 'boolean'\n ? { mergeQuery: mergeQueryOrOutputParams }\n : mergeQueryOrOutputParams;\n\n const query = outputParams?.mergeQuery\n ? { ...this.query.data, ...rawQuery }\n : (rawQuery ?? {});\n\n this._compiler ??= compile(this.tokenData);\n\n const defaultUrlCreateParams: UrlCreateParams<TInputParams> = {\n baseUrl: this.baseUrl,\n params: params as TInputParams,\n query,\n };\n const urlCreateParams: UrlCreateParams<TInputParams> =\n this.config.createUrl?.(defaultUrlCreateParams, this.query.data) ??\n routeConfig.get().createUrl?.(defaultUrlCreateParams, this.query.data) ??\n defaultUrlCreateParams;\n\n const path = this._compiler(this.processParams(urlCreateParams.params));\n\n const url = `${urlCreateParams.baseUrl || ''}${this.isHash ? '#' : ''}${path}`;\n\n if (outputParams?.omitQuery) {\n return url;\n }\n\n return `${url}${buildSearchString(urlCreateParams.query)}`;\n }\n\n /**\n * Navigates to this route.\n *\n * [**Documentation**](https://js2me.github.io/mobx-route/core/Route.html#open-args)\n */\n open(\n ...args: IsPartial<TInputParams> extends true\n ? [\n params?: TInputParams | null | undefined,\n navigateParams?: RouteNavigateParams,\n ]\n : [params: TInputParams, navigateParams?: RouteNavigateParams]\n ): Promise<void>;\n open(\n ...args: IsPartial<TInputParams> extends true\n ? [\n params?: TInputParams | null | undefined,\n replace?: RouteNavigateParams['replace'],\n query?: RouteNavigateParams['query'],\n ]\n : [\n params: TInputParams,\n replace?: RouteNavigateParams['replace'],\n query?: RouteNavigateParams['query'],\n ]\n ): Promise<void>;\n open(url: string, navigateParams?: RouteNavigateParams): Promise<void>;\n open(\n url: string,\n replace?: RouteNavigateParams['replace'],\n query?: RouteNavigateParams['query'],\n ): Promise<void>;\n\n /**\n * Navigates to this route.\n *\n * [**Documentation**](https://js2me.github.io/mobx-route/core/Route.html#open-args)\n */\n async open(...args: any[]) {\n const {\n replace,\n state: rawState,\n query: rawQuery,\n mergeQuery: rawMergeQuery,\n } = typeof args[1] === 'boolean' || args.length > 2\n ? ({ replace: args[1], query: args[2] } as RouteNavigateParams)\n : ((args[1] ?? {}) as RouteNavigateParams);\n let url: string;\n let params: Maybe<InputPathParams<TPath>>;\n\n const mergeQuery = rawMergeQuery ?? this.isAbleToMergeQuery;\n const query = mergeQuery ? { ...this.query.data, ...rawQuery } : rawQuery;\n\n if (typeof args[0] === 'string') {\n url = args[0];\n } else {\n params = args[0] as InputPathParams<TPath>;\n url = this.createUrl(args[0], query);\n }\n\n const state = rawState ?? null;\n\n const trx: NavigationTrx<TInputParams> = {\n url,\n params: params as TInputParams,\n replace,\n state,\n query,\n };\n\n const isConfirmed = await this.confirmOpening(trx);\n\n if (!isConfirmed) {\n return;\n }\n\n this.skipPathMatchCheck = true;\n\n if (trx.replace) {\n this.history.replace(trx.url, trx.state);\n } else {\n this.history.push(trx.url, trx.state);\n }\n }\n\n protected get tokenData() {\n if (!this._tokenData) {\n this._tokenData = parse(this.path, this.config.parseOptions);\n }\n return this._tokenData;\n }\n\n protected async confirmOpening(trx: NavigationTrx<TInputParams>) {\n this.status = 'opening';\n\n if (this.config.beforeOpen) {\n const feedback = await this.config.beforeOpen(trx);\n\n if (feedback === false) {\n runInAction(() => {\n this.status = 'open-rejected';\n });\n return false;\n }\n\n if (typeof feedback === 'object') {\n runInAction(() => {\n this.status = 'open-confirmed';\n });\n\n return Object.assign(trx, feedback);\n }\n }\n\n runInAction(() => {\n this.status = 'open-confirmed';\n });\n\n return true;\n }\n\n protected confirmClosing() {\n this.status = 'closed';\n return true;\n }\n\n private firstPathMatchingRun = true;\n\n private checkPathMatch = async (isPathMathched: boolean) => {\n if (this.firstPathMatchingRun) {\n this.firstPathMatchingRun = false;\n // ignore first 'afterClose' callback call\n if (!isPathMathched) {\n return;\n }\n }\n\n if (this.skipPathMatchCheck) {\n // after open\n this.skipPathMatchCheck = false;\n return;\n }\n\n if (isPathMathched) {\n const trx: NavigationTrx<TInputParams> = {\n url: this.parsedPathData!.path,\n params: this.parsedPathData!.params as TInputParams,\n state: this.history.location.state,\n query: this.query.data,\n };\n\n const nextTrxOrConfirmed = await this.confirmOpening(trx);\n\n if (!nextTrxOrConfirmed) {\n return;\n }\n\n this.config.afterOpen?.(this.parsedPathData!, this);\n\n if (typeof nextTrxOrConfirmed === 'object') {\n if (nextTrxOrConfirmed.replace) {\n this.history.replace(\n nextTrxOrConfirmed.url,\n nextTrxOrConfirmed.state,\n );\n } else {\n this.history.push(nextTrxOrConfirmed.url, nextTrxOrConfirmed.state);\n }\n }\n\n return;\n } else {\n const isConfirmed = this.confirmClosing();\n\n if (isConfirmed) {\n this.config.afterClose?.();\n }\n }\n };\n\n private get isAbleToMergeQuery() {\n return this.config.mergeQuery ?? routeConfig.get().mergeQuery;\n }\n\n destroy() {\n this.abortController.abort();\n }\n}\n\nexport const createRoute = <\n TPath extends string,\n TInputParams extends InputPathParams<TPath> = InputPathParams<TPath>,\n TOutputParams extends AnyObject = ParsedPathParams<TPath>,\n TParentRoute extends Route<any, any, any, any> | null = null,\n>(\n path: TPath,\n config?: RouteConfiguration<TPath, TInputParams, TOutputParams, TParentRoute>,\n) => new Route<TPath, TInputParams, TOutputParams, TParentRoute>(path, config);\n","import { computed, makeObservable, observable } from 'mobx';\n\nimport type {\n AbstractRouteGroup,\n AnyRouteEntity,\n RoutesCollection,\n} from './route-group.types.js';\n\ndeclare const process: { env: { NODE_ENV?: string } };\n\n/**\n * Class for grouping related routes and managing their state.\n *\n * [**Documentation**](https://js2me.github.io/mobx-route/core/RouteGroup.html)\n */\nexport class RouteGroup<TRoutesCollection extends RoutesCollection>\n implements AbstractRouteGroup<TRoutesCollection>\n{\n routes: TRoutesCollection;\n\n constructor(\n routes: TRoutesCollection,\n private _indexRoute?: AnyRouteEntity,\n ) {\n this.routes = routes;\n\n computed.struct(this, 'isOpened');\n computed.struct(this, 'indexRoute');\n observable.shallow(this, 'routes');\n makeObservable(this);\n }\n\n /**\n * Returns true if at least one route in the group is open.\n *\n * [**Documentation**](https://js2me.github.io/mobx-route/core/RouteGroup.html#isopened-boolean)\n */\n get isOpened(): boolean {\n const routes = Object.values(this.routes);\n return routes.some(\n (route) =>\n route.isOpened ||\n ('hasOpenedChildren' in route && route.hasOpenedChildren),\n );\n }\n\n /**\n * First found index route.\n *\n * [**Documentation**](https://js2me.github.io/mobx-route/core/RouteGroup.html#indexroute-route-undefined)\n */\n get indexRoute(): AnyRouteEntity | undefined {\n return (this._indexRoute ??\n Object.values(this.routes).find(\n (route) => 'isIndex' in route && route.isIndex,\n )) as unknown as AnyRouteEntity;\n }\n\n /**\n * Main navigation method for the group.\n *\n * [**Documentation**](https://js2me.github.io/mobx-route/core/RouteGroup.html#open-args-any-void)\n */\n open(...args: any[]) {\n let lastGroupRoute: RouteGroup<any> | undefined;\n\n if (this.indexRoute && 'open' in this.indexRoute) {\n this.indexRoute.open(...args);\n return;\n }\n\n for (const routeName in this.routes) {\n const route = this.routes[routeName];\n if (route instanceof RouteGroup) {\n lastGroupRoute = route;\n }\n }\n\n if (lastGroupRoute) {\n lastGroupRoute.open(...args);\n } else if (process.env.NODE_ENV !== 'production') {\n console.warn(\n \"RouteGroup doesn't have index route. open() method doesn't work.\",\n );\n }\n }\n}\n\nexport const createRouteGroup = <TRoutesCollection extends RoutesCollection>(\n routes: TRoutesCollection,\n indexRoute?: AnyRouteEntity,\n) => new RouteGroup<TRoutesCollection>(routes, indexRoute);\n","import { computed, makeObservable } from 'mobx';\nimport {\n buildSearchString,\n type History,\n type IQueryParams,\n} from 'mobx-location-history';\n\nimport { routeConfig } from '../config/index.js';\nimport type { RoutesCollection } from '../route-group/index.js';\n\nimport type {\n RouterConfiguration,\n RouterNavigateOptions,\n} from './router.types.js';\n\n/**\n * Class for centralized routing management.\n *\n * [**Documentation**](https://js2me.github.io/mobx-route/core/Router.html)\n */\nexport class Router<TRoutesCollection extends RoutesCollection> {\n routes: TRoutesCollection;\n history: History;\n query: IQueryParams;\n\n constructor(config: RouterConfiguration<TRoutesCollection>) {\n this.routes = config.routes;\n this.history = config.history ?? routeConfig.get().history;\n this.query = config.queryParams ?? routeConfig.get().queryParams;\n\n computed.struct(this, 'location');\n\n makeObservable(this);\n }\n\n get location() {\n return this.history.location;\n }\n\n navigate(url: string, options?: RouterNavigateOptions) {\n const query =\n (options?.mergeQuery ?? routeConfig.get().mergeQuery)\n ? { ...this.query.data, ...options?.query }\n : { ...options?.query };\n\n const searchString = buildSearchString(query);\n const navigationUrl = `${url}${searchString}`;\n\n if (options?.replace) {\n this.history.replace(navigationUrl, options?.state);\n } else {\n this.history.push(navigationUrl, options?.state);\n }\n }\n}\n\nexport const createRouter = <TRoutesCollection extends RoutesCollection>(\n config: RouterConfiguration<TRoutesCollection>,\n) => new Router(config);\n","import type { AnyRouteEntity } from '../route-group/index.js';\n\nexport const isRouteEntity = (route: any): route is AnyRouteEntity =>\n route && 'isOpened' in route;\n","import { LinkedAbortController } from 'linked-abort-controller';\nimport {\n action,\n computed,\n makeObservable,\n observable,\n onBecomeObserved,\n onBecomeUnobserved,\n reaction,\n runInAction,\n} from 'mobx';\nimport type { IQueryParams } from 'mobx-location-history';\nimport { callFunction } from 'yummies/common';\nimport type { AnyObject, EmptyObject, IsPartial, Maybe } from 'yummies/types';\n\nimport { routeConfig } from '../config/index.js';\n\nimport type {\n AbstractVirtualRoute,\n VirtualOpenExtraParams,\n VirtualRouteConfiguration,\n} from './virtual-route.types.js';\n\n/**\n * Class for creating routes with custom activation logic\n *\n * [**Documentation**](https://js2me.github.io/mobx-route/core/VirtualRoute.html)\n */\nexport class VirtualRoute<TParams extends AnyObject | EmptyObject = EmptyObject>\n implements AbstractVirtualRoute<TParams>\n{\n protected abortController: AbortController;\n query: IQueryParams;\n params: TParams | null;\n\n private isLocalOpened: boolean;\n\n private openChecker: Maybe<VirtualRouteConfiguration<TParams>['checkOpened']>;\n private reactionDisposer: Maybe<VoidFunction>;\n\n constructor(protected config: VirtualRouteConfiguration<TParams> = {}) {\n this.abortController = new LinkedAbortController(config.abortSignal);\n this.query = config.queryParams ?? routeConfig.get().queryParams;\n this.params = callFunction(config.initialParams, this) ?? null;\n this.openChecker = config.checkOpened;\n this.isLocalOpened = this.openChecker?.(this) ?? false;\n\n observable(this, 'params');\n observable.ref(this, 'isLocalOpened');\n observable.ref(this, '_isOpened');\n computed.struct(this, 'isOpened');\n action(this, 'setOpenChecker');\n action(this, 'open');\n action(this, 'close');\n makeObservable(this);\n\n onBecomeObserved(this, 'isOpened', () => {\n if (!config.afterOpen && !config.afterClose) {\n return;\n }\n\n this.reactionDisposer = reaction(\n () => this.isOpened,\n this.processOpenedState,\n {\n signal: this.abortController.signal,\n fireImmediately: true,\n },\n );\n });\n onBecomeUnobserved(this, 'isOpened', () => {\n this.reactionDisposer?.();\n this.reactionDisposer = undefined;\n });\n }\n\n /**\n * [**Documentation**](https://js2me.github.io/mobx-route/core/VirtualRoute.html#isopened-boolean)\n */\n get isOpened() {\n const isOuterOpened = this.openChecker == null || this.openChecker(this);\n return this.isLocalOpened && isOuterOpened;\n }\n\n /**\n * [**Documentation**](https://js2me.github.io/mobx-route/core/VirtualRoute.html#setopenchecker-openchecker-void)\n */\n setOpenChecker(\n openChecker: Maybe<VirtualRouteConfiguration<TParams>['checkOpened']>,\n ) {\n this.openChecker = openChecker;\n }\n\n /**\n * [**Documentation**](https://js2me.github.io/mobx-route/core/VirtualRoute.html#open-params-extraparams-query-replace-promise-void)\n */\n open(\n ...args: IsPartial<TParams> extends true\n ? [params?: Maybe<TParams>, extraParams?: VirtualOpenExtraParams]\n : [params: TParams, extraParams?: VirtualOpenExtraParams]\n ): Promise<void>;\n async open(...args: any[]) {\n const params = (args[0] ?? {}) as unknown as TParams;\n const extraParams: Maybe<VirtualOpenExtraParams> = args[1];\n\n if (this.config.beforeOpen) {\n const beforeOpenResult = await this.config.beforeOpen(params, this);\n if (beforeOpenResult === false) {\n return;\n }\n }\n\n if (this.config.open == null) {\n runInAction(() => {\n this.isLocalOpened = true;\n });\n } else {\n const result = await this.config.open(params, this);\n // because result can return void so this is truthy for opening state\n runInAction(() => {\n this.isLocalOpened = result !== false;\n });\n }\n\n if (!this.isLocalOpened) {\n return;\n }\n\n if (extraParams?.query) {\n this.query.update(extraParams.query, extraParams.replace);\n }\n\n runInAction(() => {\n this.params = params;\n });\n\n if (!this.reactionDisposer && this.isOpened) {\n this.config.afterOpen?.(this.params!, this);\n }\n }\n\n /**\n * [**Documentation**](https://js2me.github.io/mobx-route/core/VirtualRoute.html#close-void)\n */\n close() {\n if (this.config.close == null) {\n this.isLocalOpened = false;\n } else {\n const result = this.config.close(this);\n // because result can return void so this is truthy for opening state\n this.isLocalOpened = result !== false;\n }\n\n this.params = null;\n }\n\n private firstOpenedStateCheck = true;\n private processOpenedState = (isOpened: boolean) => {\n if (this.firstOpenedStateCheck) {\n this.firstOpenedStateCheck = false;\n // ignore first 'afterClose' callback call\n if (!isOpened) {\n return;\n }\n }\n\n if (isOpened) {\n this.config.afterOpen?.(this.params!, this);\n } else {\n this.config.afterClose?.();\n }\n };\n\n destroy() {\n this.abortController.abort();\n }\n}\n\nexport const createVirtualRoute = <\n TParams extends AnyObject | EmptyObject = EmptyObject,\n>(\n config?: VirtualRouteConfiguration<TParams>,\n) => new VirtualRoute<TParams>(config);\n"],"names":[],"mappings":";;;;;;;AAWA,IAAI;AAEG,MAAM,cAAc;AAAA,EACzB,CAAC,WAAW;AACV,QAAI,gBAAgB,QAAQ,WAAW,oBAAoB,YAAY,GAAG;AACxE,mBAAa,QAAA;AAAA,IACf;AAEA,QAAI;AAEJ,QAAI,QAAQ,SAAS;AACnB,gBAAU,OAAO;AAAA,IACnB,OAAO;AACL,gBAAU,eAAe,qBAAA;AAAA,IAC3B;AAEA,QAAI;AAEJ,QAAI,QAAQ,WAAW,CAAC,OAAO,aAAa;AAC1C,oBAAc,IAAI,YAAY,EAAE,SAAS;AAAA,IAC3C,OAAO;AACL,UAAI,QAAQ,aAAa;AACvB,sBAAc,OAAO;AAAA,MACvB,OAAO;AACL,sBAAc,IAAI,YAAY,EAAE,SAAS;AAAA,MAC3C;AAAA,IACF;AAEA,WAAO;AAAA,MACL,GAAG;AAAA,MACH;AAAA,MACA;AAAA,MACA;AAAA,IAAA;AAAA,EAEJ;AAAA,EACA,OAAO,IAAI,mBAAmB;AAChC;ACNO,MAAM,MAMb;AAAA,EAqCE,YACS,MACG,SAKN,IACJ;AAPO,SAAA,OAAA;AACG,SAAA,SAAA;AAOV,SAAK,kBAAkB,IAAI,sBAAsB,OAAO,WAAW;AACnE,SAAK,UAAU,OAAO,WAAW,YAAY,MAAM;AACnD,SAAK,QAAQ,OAAO,eAAe,YAAY,MAAM;AACrD,SAAK,UAAU,CAAC,CAAC,KAAK,OAAO;AAC7B,SAAK,SAAS,CAAC,CAAC,KAAK,OAAO;AAC5B,SAAK,OAAO,KAAK,OAAO;AACxB,SAAK,SAAS;AACd,SAAK,SAAS,OAAO,UAAW;AAEhC,aAAS,MAAM,eAAe;AAC9B,aAAS,MAAM,UAAU;AACzB,aAAS,OAAO,MAAM,MAAM;AAC5B,aAAS,OAAO,MAAM,QAAQ;AAC9B,aAAS,MAAM,aAAa;AAC5B,aAAS,MAAM,mBAAmB;AAClC,aAAS,MAAM,oBAAoB;AACnC,aAAS,MAAM,SAAS;AAExB,eAAW,MAAM,UAAU;AAC3B,eAAW,IAAI,MAAM,QAAQ;AAC7B,eAAW,IAAI,MAAM,QAAQ;AAC7B,aAAS,MAAM,WAAW;AAC1B,WAAO,MAAM,aAAa;AAC1B,WAAO,MAAM,gBAAgB;AAC7B,WAAO,MAAM,gBAAgB;AAC7B,WAAO,MAAM,gBAAgB;AAE7B,mBAAe,IAAI;AAEnB,aAAS,MAAM,KAAK,eAAe,KAAK,gBAAgB;AAAA,MACtD,QAAQ,KAAK,gBAAgB;AAAA,MAC7B,iBAAiB;AAAA,IAAA,CAClB;AAAA,EACH;AAAA,EA9EU;AAAA,EACA;AAAA,EACV;AAAA,EAEA;AAAA,EAEQ;AAAA,EACA;AAAA,EACA;AAAA,EACA,qBAAqB;AAAA,EAEnB;AAAA,EAOV;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA;AAAA,EAEA,WAAuB,CAAA;AAAA,EA8CvB,IAAc,UAAU;AACtB,UAAM,UAAU,KAAK,OAAO,WAAW,YAAY,MAAM;AACzD,WAAO,SAAS,SAAS,GAAG,IAAI,QAAQ,MAAM,GAAG,EAAE,IAAI;AAAA,EACzD;AAAA,EAEA,IAAc,iBAA+C;AAC3D,QAAI;AAEJ,QAAI,KAAK,QAAQ;AACf,wBAAkB,KAAK,QAAQ,SAAS,KAAK,MAAM,CAAC;AAAA,IACtD,OAAO;AACL,wBAAkB,KAAK,QAAQ,SAAS;AAAA,IAC1C;AAEA,QAAI,KAAK,SAAS;AAChB,UAAI,CAAC,KAAK,QAAQ,SAAS,SAAS,WAAW,KAAK,OAAO,GAAG;AAC5D,eAAO;AAAA,MACT;AAEA,wBAAkB,gBAAgB,QAAQ,KAAK,SAAS,EAAE;AAAA,IAC5D;AAEA,SACG,KAAK,SAAS,MAAM,KAAK,SAAS,SAClC,oBAAoB,OAAO,oBAAoB,KAChD;AACA,aAAO,EAAE,QAAQ,IAAW,MAAM,gBAAA;AAAA,IACpC;AAEA,SAAK,aAAa,MAAM,KAAK,WAAW;AAAA,MACtC,KAAK,KAAK,OAAO,SAAS;AAAA,MAC1B,GAAG,KAAK,OAAO;AAAA,IAAA,CAChB;AACD,UAAM,SAAS,KAAK,SAAS,eAAe;AAE5C,QAAI,WAAW,OAAO;AACpB,aAAO;AAAA,IACT;AAEA,WAAO;AAAA,EACT;AAAA,EAEA,IAAI,YAAY;AACd,WAAO,KAAK,WAAW;AAAA,EACzB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,IAAI,cAA6B;AAC/B,WAAO,KAAK,gBAAgB,QAAQ;AAAA,EACtC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,IAAI,SAA+B;AACjC,QAAI,CAAC,KAAK,gBAAgB,QAAQ;AAChC,aAAO;AAAA,IACT;AAEA,QAAI,SACD,KAAK,gBAAgB,UAA8C;AAEtE,QAAI,KAAK,OAAO,QAAQ;AACtB,YAAM,SAAS,KAAK,OAAO;AAAA,QACzB,KAAK,eAAe;AAAA,QACpB,KAAK,OAAO;AAAA,MAAA;AAEd,UAAI,QAAQ;AACV,iBAAS;AAAA,MACX,OAAO;AACL,eAAO;AAAA,MACT;AAAA,IACF;AAEA,WAAO;AAAA,EACT;AAAA,EAEA,IAAc,gBAAgB;AAC5B,WAAO,KAAK,mBAAmB;AAAA,EACjC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,IAAI,WAAW;AACb,QACE,CAAC,KAAK,iBACN,KAAK,WAAW,QAChB,KAAK,WAAW,kBAChB;AACA,aAAO;AAAA,IACT;AAEA,WACE,CAAC,KAAK,OAAO,eAAe,KAAK,OAAO,YAAY,KAAK,cAAe;AAAA,EAE5E;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,OAOE,MACA,QASA;AAIA,UAAM,EAAE,OAAO,QAAQ,GAAG,uBAAA,IAA2B,KAAK;AAE1D,UAAM,gBAAgB,IAAI,MAKxB,GAAG,KAAK,IAAI,GAAG,IAAI,IAAI;AAAA,MACvB,GAAG;AAAA,MACH,GAAG;AAAA,MACH,QAAQ;AAAA,IAAA,CACF;AAER,SAAK,YAAY,aAAoB;AAErC,WAAO;AAAA,EACT;AAAA,EAEA,eAAe,QAAoB;AACjC,SAAK,SAAS,KAAK,GAAG,MAAM;AAAA,EAC9B;AAAA,EAEA,kBAAkB,QAAoB;AACpC,SAAK,WAAW,KAAK,SAAS,OAAO,CAAC,UAAU,CAAC,OAAO,SAAS,KAAK,CAAC;AAAA,EACzE;AAAA;AAAA;AAAA;AAAA,EAKA,IAAI,oBAA6B;AAC/B,WAAO,KAAK,SAAS;AAAA,MACnB,CAAC,UAAU,MAAM,YAAY,MAAM;AAAA,IAAA;AAAA,EAEvC;AAAA,EAEU,cACR,QACuB;AACvB,QAAI,UAAU,KAAM,QAAO;AAE3B,WAAO,OAAO,QAAQ,MAAM,EAAE,OAAO,CAAC,KAAK,CAAC,KAAK,KAAK,MAAM;AAC1D,UAAI,SAAS,MAAM;AACjB,YAAI,GAAG,IAAI,MAAM,QAAQ,KAAK,IAAI,MAAM,IAAI,MAAM,IAAI,OAAO,KAAK;AAAA,MACpE;AACA,aAAO;AAAA,IACT,GAAG,CAAA,CAAe;AAAA,EACpB;AAAA,EAEA,aACK,MAWH;AACA,UAAM,SAAS,KAAK,CAAC;AACrB,UAAM,WAAW,KAAK,CAAC;AACvB,UAAM,2BAA2B,KAAK,CAAC,KAAK,KAAK;AACjD,UAAM,eACJ,OAAO,6BAA6B,YAChC,EAAE,YAAY,6BACd;AAEN,UAAM,QAAQ,cAAc,aACxB,EAAE,GAAG,KAAK,MAAM,MAAM,GAAG,SAAA,IACxB,YAAY,CAAA;AAEjB,SAAK,cAAc,QAAQ,KAAK,SAAS;AAEzC,UAAM,yBAAwD;AAAA,MAC5D,SAAS,KAAK;AAAA,MACd;AAAA,MACA;AAAA,IAAA;AAEF,UAAM,kBACJ,KAAK,OAAO,YAAY,wBAAwB,KAAK,MAAM,IAAI,KAC/D,YAAY,MAAM,YAAY,wBAAwB,KAAK,MAAM,IAAI,KACrE;AAEF,UAAM,OAAO,KAAK,UAAU,KAAK,cAAc,gBAAgB,MAAM,CAAC;AAEtE,UAAM,MAAM,GAAG,gBAAgB,WAAW,EAAE,GAAG,KAAK,SAAS,MAAM,EAAE,GAAG,IAAI;AAE5E,QAAI,cAAc,WAAW;AAC3B,aAAO;AAAA,IACT;AAEA,WAAO,GAAG,GAAG,GAAG,kBAAkB,gBAAgB,KAAK,CAAC;AAAA,EAC1D;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAwCA,MAAM,QAAQ,MAAa;AACzB,UAAM;AAAA,MACJ;AAAA,MACA,OAAO;AAAA,MACP,OAAO;AAAA,MACP,YAAY;AAAA,IAAA,IACV,OAAO,KAAK,CAAC,MAAM,aAAa,KAAK,SAAS,IAC7C,EAAE,SAAS,KAAK,CAAC,GAAG,OAAO,KAAK,CAAC,MAChC,KAAK,CAAC,KAAK,CAAA;AACjB,QAAI;AACJ,QAAI;AAEJ,UAAM,aAAa,iBAAiB,KAAK;AACzC,UAAM,QAAQ,aAAa,EAAE,GAAG,KAAK,MAAM,MAAM,GAAG,SAAA,IAAa;AAEjE,QAAI,OAAO,KAAK,CAAC,MAAM,UAAU;AAC/B,YAAM,KAAK,CAAC;AAAA,IACd,OAAO;AACL,eAAS,KAAK,CAAC;AACf,YAAM,KAAK,UAAU,KAAK,CAAC,GAAG,KAAK;AAAA,IACrC;AAEA,UAAM,QAAQ,YAAY;AAE1B,UAAM,MAAmC;AAAA,MACvC;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IAAA;AAGF,UAAM,cAAc,MAAM,KAAK,eAAe,GAAG;AAEjD,QAAI,CAAC,aAAa;AAChB;AAAA,IACF;AAEA,SAAK,qBAAqB;AAE1B,QAAI,IAAI,SAAS;AACf,WAAK,QAAQ,QAAQ,IAAI,KAAK,IAAI,KAAK;AAAA,IACzC,OAAO;AACL,WAAK,QAAQ,KAAK,IAAI,KAAK,IAAI,KAAK;AAAA,IACtC;AAAA,EACF;AAAA,EAEA,IAAc,YAAY;AACxB,QAAI,CAAC,KAAK,YAAY;AACpB,WAAK,aAAa,MAAM,KAAK,MAAM,KAAK,OAAO,YAAY;AAAA,IAC7D;AACA,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,MAAgB,eAAe,KAAkC;AAC/D,SAAK,SAAS;AAEd,QAAI,KAAK,OAAO,YAAY;AAC1B,YAAM,WAAW,MAAM,KAAK,OAAO,WAAW,GAAG;AAEjD,UAAI,aAAa,OAAO;AACtB,oBAAY,MAAM;AAChB,eAAK,SAAS;AAAA,QAChB,CAAC;AACD,eAAO;AAAA,MACT;AAEA,UAAI,OAAO,aAAa,UAAU;AAChC,oBAAY,MAAM;AAChB,eAAK,SAAS;AAAA,QAChB,CAAC;AAED,eAAO,OAAO,OAAO,KAAK,QAAQ;AAAA,MACpC;AAAA,IACF;AAEA,gBAAY,MAAM;AAChB,WAAK,SAAS;AAAA,IAChB,CAAC;AAED,WAAO;AAAA,EACT;AAAA,EAEU,iBAAiB;AACzB,SAAK,SAAS;AACd,WAAO;AAAA,EACT;AAAA,EAEQ,uBAAuB;AAAA,EAEvB,iBAAiB,OAAO,mBAA4B;AAC1D,QAAI,KAAK,sBAAsB;AAC7B,WAAK,uBAAuB;AAE5B,UAAI,CAAC,gBAAgB;AACnB;AAAA,MACF;AAAA,IACF;AAEA,QAAI,KAAK,oBAAoB;AAE3B,WAAK,qBAAqB;AAC1B;AAAA,IACF;AAEA,QAAI,gBAAgB;AAClB,YAAM,MAAmC;AAAA,QACvC,KAAK,KAAK,eAAgB;AAAA,QAC1B,QAAQ,KAAK,eAAgB;AAAA,QAC7B,OAAO,KAAK,QAAQ,SAAS;AAAA,QAC7B,OAAO,KAAK,MAAM;AAAA,MAAA;AAGpB,YAAM,qBAAqB,MAAM,KAAK,eAAe,GAAG;AAExD,UAAI,CAAC,oBAAoB;AACvB;AAAA,MACF;AAEA,WAAK,OAAO,YAAY,KAAK,gBAAiB,IAAI;AAElD,UAAI,OAAO,uBAAuB,UAAU;AAC1C,YAAI,mBAAmB,SAAS;AAC9B,eAAK,QAAQ;AAAA,YACX,mBAAmB;AAAA,YACnB,mBAAmB;AAAA,UAAA;AAAA,QAEvB,OAAO;AACL,eAAK,QAAQ,KAAK,mBAAmB,KAAK,mBAAmB,KAAK;AAAA,QACpE;AAAA,MACF;AAEA;AAAA,IACF,OAAO;AACL,YAAM,cAAc,KAAK,eAAA;AAEzB,UAAI,aAAa;AACf,aAAK,OAAO,aAAA;AAAA,MACd;AAAA,IACF;AAAA,EACF;AAAA,EAEA,IAAY,qBAAqB;AAC/B,WAAO,KAAK,OAAO,cAAc,YAAY,MAAM;AAAA,EACrD;AAAA,EAEA,UAAU;AACR,SAAK,gBAAgB,MAAA;AAAA,EACvB;AACF;AAEO,MAAM,cAAc,CAMzB,MACA,WACG,IAAI,MAAwD,MAAM,MAAM;AC1hBtE,MAAM,WAEb;AAAA,EAGE,YACE,QACQ,aACR;AADQ,SAAA,cAAA;AAER,SAAK,SAAS;AAEd,aAAS,OAAO,MAAM,UAAU;AAChC,aAAS,OAAO,MAAM,YAAY;AAClC,eAAW,QAAQ,MAAM,QAAQ;AACjC,mBAAe,IAAI;AAAA,EACrB;AAAA,EAZA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAmBA,IAAI,WAAoB;AACtB,UAAM,SAAS,OAAO,OAAO,KAAK,MAAM;AACxC,WAAO,OAAO;AAAA,MACZ,CAAC,UACC,MAAM,YACL,uBAAuB,SAAS,MAAM;AAAA,IAAA;AAAA,EAE7C;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,IAAI,aAAyC;AAC3C,WAAQ,KAAK,eACX,OAAO,OAAO,KAAK,MAAM,EAAE;AAAA,MACzB,CAAC,UAAU,aAAa,SAAS,MAAM;AAAA,IAAA;AAAA,EAE7C;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,QAAQ,MAAa;AACnB,QAAI;AAEJ,QAAI,KAAK,cAAc,UAAU,KAAK,YAAY;AAChD,WAAK,WAAW,KAAK,GAAG,IAAI;AAC5B;AAAA,IACF;AAEA,eAAW,aAAa,KAAK,QAAQ;AACnC,YAAM,QAAQ,KAAK,OAAO,SAAS;AACnC,UAAI,iBAAiB,YAAY;AAC/B,yBAAiB;AAAA,MACnB;AAAA,IACF;AAEA,QAAI,gBAAgB;AAClB,qBAAe,KAAK,GAAG,IAAI;AAAA,IAC7B,WAAW,QAAQ,IAAI,aAAa,cAAc;AAChD,cAAQ;AAAA,QACN;AAAA,MAAA;AAAA,IAEJ;AAAA,EACF;AACF;AAEO,MAAM,mBAAmB,CAC9B,QACA,eACG,IAAI,WAA8B,QAAQ,UAAU;ACvElD,MAAM,OAAmD;AAAA,EAC9D;AAAA,EACA;AAAA,EACA;AAAA,EAEA,YAAY,QAAgD;AAC1D,SAAK,SAAS,OAAO;AACrB,SAAK,UAAU,OAAO,WAAW,YAAY,MAAM;AACnD,SAAK,QAAQ,OAAO,eAAe,YAAY,MAAM;AAErD,aAAS,OAAO,MAAM,UAAU;AAEhC,mBAAe,IAAI;AAAA,EACrB;AAAA,EAEA,IAAI,WAAW;AACb,WAAO,KAAK,QAAQ;AAAA,EACtB;AAAA,EAEA,SAAS,KAAa,SAAiC;AACrD,UAAM,QACH,SAAS,cAAc,YAAY,IAAA,EAAM,aACtC,EAAE,GAAG,KAAK,MAAM,MAAM,GAAG,SAAS,MAAA,IAClC,EAAE,GAAG,SAAS,MAAA;AAEpB,UAAM,eAAe,kBAAkB,KAAK;AAC5C,UAAM,gBAAgB,GAAG,GAAG,GAAG,YAAY;AAE3C,QAAI,SAAS,SAAS;AACpB,WAAK,QAAQ,QAAQ,eAAe,SAAS,KAAK;AAAA,IACpD,OAAO;AACL,WAAK,QAAQ,KAAK,eAAe,SAAS,KAAK;AAAA,IACjD;AAAA,EACF;AACF;AAEO,MAAM,eAAe,CAC1B,WACG,IAAI,OAAO,MAAM;ACxDf,MAAM,gBAAgB,CAAC,UAC5B,SAAS,cAAc;ACyBlB,MAAM,aAEb;AAAA,EAUE,YAAsB,SAA6C,IAAI;AAAjD,SAAA,SAAA;AACpB,SAAK,kBAAkB,IAAI,sBAAsB,OAAO,WAAW;AACnE,SAAK,QAAQ,OAAO,eAAe,YAAY,MAAM;AACrD,SAAK,SAAS,aAAa,OAAO,eAAe,IAAI,KAAK;AAC1D,SAAK,cAAc,OAAO;AAC1B,SAAK,gBAAgB,KAAK,cAAc,IAAI,KAAK;AAEjD,eAAW,MAAM,QAAQ;AACzB,eAAW,IAAI,MAAM,eAAe;AACpC,eAAW,IAAI,MAAM,WAAW;AAChC,aAAS,OAAO,MAAM,UAAU;AAChC,WAAO,MAAM,gBAAgB;AAC7B,WAAO,MAAM,MAAM;AACnB,WAAO,MAAM,OAAO;AACpB,mBAAe,IAAI;AAEnB,qBAAiB,MAAM,YAAY,MAAM;AACvC,UAAI,CAAC,OAAO,aAAa,CAAC,OAAO,YAAY;AAC3C;AAAA,MACF;AAEA,WAAK,mBAAmB;AAAA,QACtB,MAAM,KAAK;AAAA,QACX,KAAK;AAAA,QACL;AAAA,UACE,QAAQ,KAAK,gBAAgB;AAAA,UAC7B,iBAAiB;AAAA,QAAA;AAAA,MACnB;AAAA,IAEJ,CAAC;AACD,uBAAmB,MAAM,YAAY,MAAM;AACzC,WAAK,mBAAA;AACL,WAAK,mBAAmB;AAAA,IAC1B,CAAC;AAAA,EACH;AAAA,EA3CU;AAAA,EACV;AAAA,EACA;AAAA,EAEQ;AAAA,EAEA;AAAA,EACA;AAAA;AAAA;AAAA;AAAA,EAyCR,IAAI,WAAW;AACb,UAAM,gBAAgB,KAAK,eAAe,QAAQ,KAAK,YAAY,IAAI;AACvE,WAAO,KAAK,iBAAiB;AAAA,EAC/B;AAAA;AAAA;AAAA;AAAA,EAKA,eACE,aACA;AACA,SAAK,cAAc;AAAA,EACrB;AAAA,EAUA,MAAM,QAAQ,MAAa;AACzB,UAAM,SAAU,KAAK,CAAC,KAAK,CAAA;AAC3B,UAAM,cAA6C,KAAK,CAAC;AAEzD,QAAI,KAAK,OAAO,YAAY;AAC1B,YAAM,mBAAmB,MAAM,KAAK,OAAO,WAAW,QAAQ,IAAI;AAClE,UAAI,qBAAqB,OAAO;AAC9B;AAAA,MACF;AAAA,IACF;AAEA,QAAI,KAAK,OAAO,QAAQ,MAAM;AAC5B,kBAAY,MAAM;AAChB,aAAK,gBAAgB;AAAA,MACvB,CAAC;AAAA,IACH,OAAO;AACL,YAAM,SAAS,MAAM,KAAK,OAAO,KAAK,QAAQ,IAAI;AAElD,kBAAY,MAAM;AAChB,aAAK,gBAAgB,WAAW;AAAA,MAClC,CAAC;AAAA,IACH;AAEA,QAAI,CAAC,KAAK,eAAe;AACvB;AAAA,IACF;AAEA,QAAI,aAAa,OAAO;AACtB,WAAK,MAAM,OAAO,YAAY,OAAO,YAAY,OAAO;AAAA,IAC1D;AAEA,gBAAY,MAAM;AAChB,WAAK,SAAS;AAAA,IAChB,CAAC;AAED,QAAI,CAAC,KAAK,oBAAoB,KAAK,UAAU;AAC3C,WAAK,OAAO,YAAY,KAAK,QAAS,IAAI;AAAA,IAC5C;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,QAAQ;AACN,QAAI,KAAK,OAAO,SAAS,MAAM;AAC7B,WAAK,gBAAgB;AAAA,IACvB,OAAO;AACL,YAAM,SAAS,KAAK,OAAO,MAAM,IAAI;AAErC,WAAK,gBAAgB,WAAW;AAAA,IAClC;AAEA,SAAK,SAAS;AAAA,EAChB;AAAA,EAEQ,wBAAwB;AAAA,EACxB,qBAAqB,CAAC,aAAsB;AAClD,QAAI,KAAK,uBAAuB;AAC9B,WAAK,wBAAwB;AAE7B,UAAI,CAAC,UAAU;AACb;AAAA,MACF;AAAA,IACF;AAEA,QAAI,UAAU;AACZ,WAAK,OAAO,YAAY,KAAK,QAAS,IAAI;AAAA,IAC5C,OAAO;AACL,WAAK,OAAO,aAAA;AAAA,IACd;AAAA,EACF;AAAA,EAEA,UAAU;AACR,SAAK,gBAAgB,MAAA;AAAA,EACvB;AACF;AAEO,MAAM,qBAAqB,CAGhC,WACG,IAAI,aAAsB,MAAM;"}
|
package/package.json
CHANGED
package/react.cjs
CHANGED
|
@@ -125,22 +125,31 @@ const RouteViewGroup = mobxReactLite.observer(
|
|
|
125
125
|
params,
|
|
126
126
|
...navigateParams
|
|
127
127
|
}) => {
|
|
128
|
-
let
|
|
128
|
+
let activeChildRouteNode = null;
|
|
129
129
|
let lastInactiveChildNode = null;
|
|
130
|
+
let hasRoutesInOpening = false;
|
|
130
131
|
const childNodes = Array.isArray(children) ? children : [children];
|
|
131
132
|
for (const childNode of childNodes) {
|
|
132
|
-
|
|
133
|
-
mobxRoute.isRouteEntity(childNode.props?.route)
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
133
|
+
const isRouteChild = react.isValidElement(childNode) && // @ts-expect-error redundand checks better to wrap in this directive
|
|
134
|
+
mobxRoute.isRouteEntity(childNode.props?.route);
|
|
135
|
+
if (isRouteChild) {
|
|
136
|
+
const route = childNode.props.route;
|
|
137
|
+
if (route.isOpened) {
|
|
138
|
+
activeChildRouteNode = childNode;
|
|
139
|
+
break;
|
|
140
|
+
} else {
|
|
141
|
+
if (route.isOpening) {
|
|
142
|
+
hasRoutesInOpening = true;
|
|
143
|
+
}
|
|
144
|
+
lastInactiveChildNode = childNode;
|
|
145
|
+
}
|
|
137
146
|
} else {
|
|
138
147
|
lastInactiveChildNode = childNode;
|
|
139
148
|
}
|
|
140
149
|
}
|
|
141
|
-
const hasActiveChildNode = !!
|
|
150
|
+
const hasActiveChildNode = !!activeChildRouteNode;
|
|
142
151
|
react.useEffect(() => {
|
|
143
|
-
if (!hasActiveChildNode && otherwiseNavigation) {
|
|
152
|
+
if (!hasActiveChildNode && !hasRoutesInOpening && otherwiseNavigation) {
|
|
144
153
|
if (typeof otherwiseNavigation === "string") {
|
|
145
154
|
const history = mobxRoute.routeConfig.get().history;
|
|
146
155
|
const url = `${otherwiseNavigation}${mobxRoute.buildSearchString(navigateParams.query || {})}`;
|
|
@@ -153,11 +162,11 @@ const RouteViewGroup = mobxReactLite.observer(
|
|
|
153
162
|
otherwiseNavigation.open(params, navigateParams);
|
|
154
163
|
}
|
|
155
164
|
}
|
|
156
|
-
}, [hasActiveChildNode, otherwiseNavigation]);
|
|
157
|
-
if (otherwiseNavigation && !
|
|
165
|
+
}, [hasActiveChildNode, hasRoutesInOpening, otherwiseNavigation]);
|
|
166
|
+
if (otherwiseNavigation && !activeChildRouteNode) {
|
|
158
167
|
return null;
|
|
159
168
|
}
|
|
160
|
-
const resultNodeToRender =
|
|
169
|
+
const resultNodeToRender = activeChildRouteNode ?? lastInactiveChildNode ?? null;
|
|
161
170
|
if (Layout) {
|
|
162
171
|
return /* @__PURE__ */ jsxRuntime.jsx(Layout, { children: resultNodeToRender });
|
|
163
172
|
}
|
package/react.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"react.cjs","sources":["../src/react/components/link.tsx","../src/react/components/route-view.tsx","../src/react/components/route-view-group.tsx"],"sourcesContent":["import { observer } from 'mobx-react-lite';\nimport {\n type AnyRoute,\n buildSearchString,\n type InputPathParams,\n parseSearchString,\n type RouteNavigateParams,\n routeConfig,\n} from 'mobx-route';\nimport {\n type AnchorHTMLAttributes,\n cloneElement,\n forwardRef,\n isValidElement,\n type MouseEvent,\n useMemo,\n useRef,\n} from 'react';\nimport { isShallowEqual } from 'yummies/data';\nimport type { IsPartial } from 'yummies/types';\n\ninterface LinkAnchorProps\n extends Omit<AnchorHTMLAttributes<HTMLAnchorElement>, 'href'> {\n asChild?: boolean;\n}\n\ntype LinkPathRouteProps<TRoute extends AnyRoute> = {\n to: TRoute;\n} & (IsPartial<InputPathParams<TRoute['path']>> extends true\n ? {\n params?: InputPathParams<TRoute['path']> | null | undefined;\n }\n : { params: InputPathParams<TRoute['path']> });\n\ntype LinkSimpleRouteProps =\n | {\n to: string;\n }\n | {\n href: string;\n };\n\nexport type LinkProps<TRoute extends AnyRoute> = LinkAnchorProps &\n RouteNavigateParams &\n (LinkPathRouteProps<TRoute> | LinkSimpleRouteProps);\n\ntype LinkComponentType = <TRoute extends AnyRoute>(\n props: LinkProps<TRoute>,\n) => React.ReactNode;\n\nexport const Link = observer(\n forwardRef<\n HTMLAnchorElement,\n LinkAnchorProps &\n RouteNavigateParams & {\n params?: any;\n to: string | AnyRoute;\n href: string;\n }\n >(\n (\n {\n to,\n href: outerHref,\n mergeQuery,\n asChild,\n children,\n params,\n // route navigate params\n query,\n replace,\n state,\n ...outerAnchorProps\n },\n ref,\n ) => {\n const isExternalNavigation =\n outerAnchorProps.target === '_blank' ||\n outerAnchorProps.target === 'blank';\n const queryDataRef = useRef<RouteNavigateParams['query']>(query);\n\n if (!isShallowEqual(queryDataRef.current, query)) {\n queryDataRef.current = query;\n }\n\n const { href, navigateParams } = useMemo(() => {\n const navigateParams: RouteNavigateParams = {\n mergeQuery,\n query,\n replace,\n state,\n };\n\n const cfg = routeConfig.get();\n\n let href: string;\n\n if (outerHref) {\n href = outerHref;\n } else {\n if (typeof to === 'string') {\n const isNeedToMergeQuery =\n navigateParams.mergeQuery ?? cfg.mergeQuery;\n\n const [path, ...querySegments] = to.split('?');\n\n const existedQuery = parseSearchString(querySegments.join('?'));\n\n const query = {\n ...(isNeedToMergeQuery ? cfg.queryParams.data : {}),\n ...existedQuery,\n ...navigateParams.query,\n };\n\n href = `${path}${buildSearchString(query)}`;\n } else {\n href = to.createUrl(\n params,\n navigateParams.query,\n navigateParams.mergeQuery,\n );\n }\n }\n\n return {\n href: cfg.formatLinkHref?.(href) ?? href,\n navigateParams,\n };\n }, [mergeQuery, replace, state, to, queryDataRef.current]);\n\n const handleClick = (event: MouseEvent<HTMLAnchorElement>) => {\n if (\n isExternalNavigation ||\n event.ctrlKey ||\n event.metaKey ||\n event.altKey ||\n event.shiftKey ||\n event.button !== 0\n )\n return;\n\n outerAnchorProps.onClick?.(event);\n\n if (!event.defaultPrevented) {\n event.preventDefault();\n\n if (navigateParams.replace) {\n routeConfig.get().history.replace(href, navigateParams.state);\n } else {\n routeConfig.get().history.push(href, navigateParams.state);\n }\n }\n };\n\n const anchorProps = {\n ...outerAnchorProps,\n href,\n onClick: handleClick,\n rel:\n outerAnchorProps.rel ??\n (isExternalNavigation ? 'noopener noreferrer' : undefined),\n };\n\n return asChild && isValidElement(children) ? (\n cloneElement(children, anchorProps)\n ) : (\n <a {...anchorProps} ref={ref}>\n {children}\n </a>\n );\n },\n ),\n) as unknown as LinkComponentType;\n","import { observer } from 'mobx-react-lite';\nimport type {\n AnyAbstractRouteEntity,\n AnyRoute,\n AnyVirtualRoute,\n} from 'mobx-route';\nimport { useRef } from 'react';\nimport { type LoadableConfig, loadable } from 'react-simple-loadable';\n\nexport type RouteViewComponent<TRoute extends AnyAbstractRouteEntity> =\n React.ComponentType<RouteViewProps<TRoute>>;\n\ninterface RouteViewConfigWithoutRoute {\n children?: React.ReactNode | (() => React.ReactNode);\n}\n\nexport interface RouteViewConfigWithRoute<TRoute extends AnyAbstractRouteEntity>\n extends Pick<LoadableConfig, 'loading' | 'preload' | 'throwOnError'> {\n route: TRoute;\n view?: RouteViewComponent<TRoute>;\n loadView?: (route: TRoute) => Promise<RouteViewComponent<TRoute>>;\n /**\n * Case when route is not opened\n */\n fallback?: React.ReactNode;\n children?:\n | React.ReactNode\n | ((\n params: RouteViewProps<TRoute>['params'],\n route: TRoute,\n ) => React.ReactNode);\n}\n\nexport type RouteViewConfig<TRoute extends AnyAbstractRouteEntity> =\n | RouteViewConfigWithRoute<TRoute>\n | RouteViewConfigWithoutRoute;\n\nexport type RouteViewProps<TRoute extends AnyAbstractRouteEntity> = {\n children?: React.ReactNode;\n params: TRoute extends AnyRoute\n ? Exclude<TRoute['params'], null | undefined>\n : TRoute extends AnyVirtualRoute\n ? TRoute['params']\n : never;\n};\n\ntype RouteViewBaseComponent = <TRoute extends AnyAbstractRouteEntity>(\n props: RouteViewConfig<TRoute>,\n) => React.ReactNode;\n\nfunction RouteViewBase<TRoute extends AnyAbstractRouteEntity>(\n props: Readonly<RouteViewConfig<TRoute>>,\n): React.ReactNode {\n // @ts-expect-error redundand pass first argument\n const lazyViewComponentRef = useRef<React.ComponentType<any>>();\n\n let Component: React.ComponentType<any> | undefined;\n\n if (!('route' in props)) {\n return typeof props.children === 'function'\n ? props.children()\n : props.children;\n }\n\n if (!props.route.isOpened) {\n return props.fallback ?? null;\n }\n\n if (props.loadView) {\n if (!lazyViewComponentRef.current) {\n lazyViewComponentRef.current = loadable({\n load: () => props.loadView!(props.route),\n loading: props.loading,\n preload: props.preload,\n throwOnError: props.throwOnError,\n });\n }\n Component = lazyViewComponentRef.current;\n } else {\n Component = props.view;\n }\n\n const params: any = 'params' in props.route ? props.route.params : {};\n\n if (Component) {\n return <Component params={params}>{props.children}</Component>;\n }\n\n if (typeof props.children === 'function') {\n return props.children(params, props.route);\n }\n\n return props.children;\n}\n\nexport const RouteView = observer(RouteViewBase) as RouteViewBaseComponent;\n","import { observer } from 'mobx-react-lite';\nimport {\n type AnyRouteEntity,\n buildSearchString,\n isRouteEntity,\n type RouteNavigateParams,\n type RouteParams,\n routeConfig,\n} from 'mobx-route';\nimport { isValidElement, useEffect } from 'react';\nimport type { IsPartial, Maybe } from 'yummies/types';\n\ntype LayoutComponent =\n | React.ComponentType<{ children?: React.ReactNode }>\n | React.ComponentType<{ children: React.ReactNode }>;\n\ninterface BaseProps extends RouteNavigateParams {\n children: React.ReactNode;\n layout?: LayoutComponent;\n}\n\ntype PropsWithDefaultRoute<TRoute extends AnyRouteEntity> = BaseProps & {\n otherwise?: TRoute;\n} & (IsPartial<RouteParams<TRoute>> extends true\n ? {\n params?: Maybe<RouteParams<TRoute>>;\n }\n : {\n params: RouteParams<TRoute>;\n });\n\ntype PropsWithDefaultUrl = BaseProps & {\n otherwise?: string;\n};\n\nexport type RouteViewGroupProps<TRoute extends AnyRouteEntity> =\n | PropsWithDefaultRoute<TRoute>\n | PropsWithDefaultUrl;\n\ntype RouteViewGroupComponent = <TRoute extends AnyRouteEntity>(\n props: RouteViewGroupProps<TRoute>,\n) => React.ReactNode;\n\nexport const RouteViewGroup = observer(\n <TRoute extends AnyRouteEntity>({\n children,\n layout: Layout,\n otherwise: otherwiseNavigation,\n // @ts-expect-error\n params,\n ...navigateParams\n }: RouteViewGroupProps<TRoute>) => {\n let activeChildNode: React.ReactNode = null;\n let lastInactiveChildNode: React.ReactNode = null;\n\n const childNodes: React.ReactNode[] = Array.isArray(children)\n ? children\n : [children];\n\n for (const childNode of childNodes) {\n if (\n isValidElement(childNode) &&\n // @ts-expect-error redundand checks better to wrap in this directive\n isRouteEntity(childNode.props?.route) &&\n // @ts-expect-error redundand checks better to wrap in this directive\n childNode.props.route.isOpened\n ) {\n activeChildNode = childNode;\n break;\n } else {\n lastInactiveChildNode = childNode;\n }\n }\n\n const hasActiveChildNode = !!activeChildNode;\n\n useEffect(() => {\n if (!hasActiveChildNode && otherwiseNavigation) {\n if (typeof otherwiseNavigation === 'string') {\n const history = routeConfig.get().history;\n const url = `${otherwiseNavigation}${buildSearchString(navigateParams.query || {})}`;\n\n if (navigateParams.replace) {\n history.replace(url, navigateParams.state);\n } else {\n history.push(url, navigateParams.state);\n }\n } else if (!otherwiseNavigation.isOpened) {\n otherwiseNavigation.open(params, navigateParams);\n }\n }\n }, [hasActiveChildNode, otherwiseNavigation]);\n\n if (otherwiseNavigation && !activeChildNode) {\n return null;\n }\n\n const resultNodeToRender = activeChildNode ?? lastInactiveChildNode ?? null;\n\n if (Layout) {\n return <Layout>{resultNodeToRender}</Layout>;\n }\n\n return resultNodeToRender;\n },\n) as unknown as RouteViewGroupComponent;\n"],"names":["observer","forwardRef","useRef","isShallowEqual","useMemo","navigateParams","routeConfig","href","parseSearchString","query","buildSearchString","isValidElement","cloneElement","jsx","loadable","isRouteEntity","useEffect"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"react.cjs","sources":["../src/react/components/link.tsx","../src/react/components/route-view.tsx","../src/react/components/route-view-group.tsx"],"sourcesContent":["import { observer } from 'mobx-react-lite';\nimport {\n type AnyRoute,\n buildSearchString,\n type InputPathParams,\n parseSearchString,\n type RouteNavigateParams,\n routeConfig,\n} from 'mobx-route';\nimport {\n type AnchorHTMLAttributes,\n cloneElement,\n forwardRef,\n isValidElement,\n type MouseEvent,\n useMemo,\n useRef,\n} from 'react';\nimport { isShallowEqual } from 'yummies/data';\nimport type { IsPartial } from 'yummies/types';\n\ninterface LinkAnchorProps\n extends Omit<AnchorHTMLAttributes<HTMLAnchorElement>, 'href'> {\n asChild?: boolean;\n}\n\ntype LinkPathRouteProps<TRoute extends AnyRoute> = {\n to: TRoute;\n} & (IsPartial<InputPathParams<TRoute['path']>> extends true\n ? {\n params?: InputPathParams<TRoute['path']> | null | undefined;\n }\n : { params: InputPathParams<TRoute['path']> });\n\ntype LinkSimpleRouteProps =\n | {\n to: string;\n }\n | {\n href: string;\n };\n\nexport type LinkProps<TRoute extends AnyRoute> = LinkAnchorProps &\n RouteNavigateParams &\n (LinkPathRouteProps<TRoute> | LinkSimpleRouteProps);\n\ntype LinkComponentType = <TRoute extends AnyRoute>(\n props: LinkProps<TRoute>,\n) => React.ReactNode;\n\nexport const Link = observer(\n forwardRef<\n HTMLAnchorElement,\n LinkAnchorProps &\n RouteNavigateParams & {\n params?: any;\n to: string | AnyRoute;\n href: string;\n }\n >(\n (\n {\n to,\n href: outerHref,\n mergeQuery,\n asChild,\n children,\n params,\n // route navigate params\n query,\n replace,\n state,\n ...outerAnchorProps\n },\n ref,\n ) => {\n const isExternalNavigation =\n outerAnchorProps.target === '_blank' ||\n outerAnchorProps.target === 'blank';\n const queryDataRef = useRef<RouteNavigateParams['query']>(query);\n\n if (!isShallowEqual(queryDataRef.current, query)) {\n queryDataRef.current = query;\n }\n\n const { href, navigateParams } = useMemo(() => {\n const navigateParams: RouteNavigateParams = {\n mergeQuery,\n query,\n replace,\n state,\n };\n\n const cfg = routeConfig.get();\n\n let href: string;\n\n if (outerHref) {\n href = outerHref;\n } else {\n if (typeof to === 'string') {\n const isNeedToMergeQuery =\n navigateParams.mergeQuery ?? cfg.mergeQuery;\n\n const [path, ...querySegments] = to.split('?');\n\n const existedQuery = parseSearchString(querySegments.join('?'));\n\n const query = {\n ...(isNeedToMergeQuery ? cfg.queryParams.data : {}),\n ...existedQuery,\n ...navigateParams.query,\n };\n\n href = `${path}${buildSearchString(query)}`;\n } else {\n href = to.createUrl(\n params,\n navigateParams.query,\n navigateParams.mergeQuery,\n );\n }\n }\n\n return {\n href: cfg.formatLinkHref?.(href) ?? href,\n navigateParams,\n };\n }, [mergeQuery, replace, state, to, queryDataRef.current]);\n\n const handleClick = (event: MouseEvent<HTMLAnchorElement>) => {\n if (\n isExternalNavigation ||\n event.ctrlKey ||\n event.metaKey ||\n event.altKey ||\n event.shiftKey ||\n event.button !== 0\n )\n return;\n\n outerAnchorProps.onClick?.(event);\n\n if (!event.defaultPrevented) {\n event.preventDefault();\n\n if (navigateParams.replace) {\n routeConfig.get().history.replace(href, navigateParams.state);\n } else {\n routeConfig.get().history.push(href, navigateParams.state);\n }\n }\n };\n\n const anchorProps = {\n ...outerAnchorProps,\n href,\n onClick: handleClick,\n rel:\n outerAnchorProps.rel ??\n (isExternalNavigation ? 'noopener noreferrer' : undefined),\n };\n\n return asChild && isValidElement(children) ? (\n cloneElement(children, anchorProps)\n ) : (\n <a {...anchorProps} ref={ref}>\n {children}\n </a>\n );\n },\n ),\n) as unknown as LinkComponentType;\n","import { observer } from 'mobx-react-lite';\nimport type {\n AnyAbstractRouteEntity,\n AnyRoute,\n AnyVirtualRoute,\n} from 'mobx-route';\nimport { useRef } from 'react';\nimport { type LoadableConfig, loadable } from 'react-simple-loadable';\n\nexport type RouteViewComponent<TRoute extends AnyAbstractRouteEntity> =\n React.ComponentType<RouteViewProps<TRoute>>;\n\ninterface RouteViewConfigWithoutRoute {\n children?: React.ReactNode | (() => React.ReactNode);\n}\n\nexport interface RouteViewConfigWithRoute<TRoute extends AnyAbstractRouteEntity>\n extends Pick<LoadableConfig, 'loading' | 'preload' | 'throwOnError'> {\n route: TRoute;\n view?: RouteViewComponent<TRoute>;\n loadView?: (route: TRoute) => Promise<RouteViewComponent<TRoute>>;\n /**\n * Case when route is not opened\n */\n fallback?: React.ReactNode;\n children?:\n | React.ReactNode\n | ((\n params: RouteViewProps<TRoute>['params'],\n route: TRoute,\n ) => React.ReactNode);\n}\n\nexport type RouteViewConfig<TRoute extends AnyAbstractRouteEntity> =\n | RouteViewConfigWithRoute<TRoute>\n | RouteViewConfigWithoutRoute;\n\nexport type RouteViewProps<TRoute extends AnyAbstractRouteEntity> = {\n children?: React.ReactNode;\n params: TRoute extends AnyRoute\n ? Exclude<TRoute['params'], null | undefined>\n : TRoute extends AnyVirtualRoute\n ? TRoute['params']\n : never;\n};\n\ntype RouteViewBaseComponent = <TRoute extends AnyAbstractRouteEntity>(\n props: RouteViewConfig<TRoute>,\n) => React.ReactNode;\n\nfunction RouteViewBase<TRoute extends AnyAbstractRouteEntity>(\n props: Readonly<RouteViewConfig<TRoute>>,\n): React.ReactNode {\n // @ts-expect-error redundand pass first argument\n const lazyViewComponentRef = useRef<React.ComponentType<any>>();\n\n let Component: React.ComponentType<any> | undefined;\n\n if (!('route' in props)) {\n return typeof props.children === 'function'\n ? props.children()\n : props.children;\n }\n\n if (!props.route.isOpened) {\n return props.fallback ?? null;\n }\n\n if (props.loadView) {\n if (!lazyViewComponentRef.current) {\n lazyViewComponentRef.current = loadable({\n load: () => props.loadView!(props.route),\n loading: props.loading,\n preload: props.preload,\n throwOnError: props.throwOnError,\n });\n }\n Component = lazyViewComponentRef.current;\n } else {\n Component = props.view;\n }\n\n const params: any = 'params' in props.route ? props.route.params : {};\n\n if (Component) {\n return <Component params={params}>{props.children}</Component>;\n }\n\n if (typeof props.children === 'function') {\n return props.children(params, props.route);\n }\n\n return props.children;\n}\n\nexport const RouteView = observer(RouteViewBase) as RouteViewBaseComponent;\n","import { observer } from 'mobx-react-lite';\nimport {\n type AnyRoute,\n type AnyRouteEntity,\n buildSearchString,\n isRouteEntity,\n type RouteNavigateParams,\n type RouteParams,\n routeConfig,\n} from 'mobx-route';\nimport { isValidElement, useEffect } from 'react';\nimport type { IsPartial, Maybe } from 'yummies/types';\n\ntype LayoutComponent =\n | React.ComponentType<{ children?: React.ReactNode }>\n | React.ComponentType<{ children: React.ReactNode }>;\n\ninterface BaseProps extends RouteNavigateParams {\n children: React.ReactNode;\n layout?: LayoutComponent;\n}\n\ntype PropsWithDefaultRoute<TRoute extends AnyRouteEntity> = BaseProps & {\n otherwise?: TRoute;\n} & (IsPartial<RouteParams<TRoute>> extends true\n ? {\n params?: Maybe<RouteParams<TRoute>>;\n }\n : {\n params: RouteParams<TRoute>;\n });\n\ntype PropsWithDefaultUrl = BaseProps & {\n otherwise?: string;\n};\n\nexport type RouteViewGroupProps<TRoute extends AnyRouteEntity> =\n | PropsWithDefaultRoute<TRoute>\n | PropsWithDefaultUrl;\n\ntype RouteViewGroupComponent = <TRoute extends AnyRouteEntity>(\n props: RouteViewGroupProps<TRoute>,\n) => React.ReactNode;\n\nexport const RouteViewGroup = observer(\n <TRoute extends AnyRouteEntity>({\n children,\n layout: Layout,\n otherwise: otherwiseNavigation,\n // @ts-expect-error\n params,\n ...navigateParams\n }: RouteViewGroupProps<TRoute>) => {\n let activeChildRouteNode: React.ReactNode = null;\n let lastInactiveChildNode: React.ReactNode = null;\n let hasRoutesInOpening = false;\n\n const childNodes: React.ReactNode[] = Array.isArray(children)\n ? children\n : [children];\n\n for (const childNode of childNodes) {\n const isRouteChild =\n isValidElement(childNode) &&\n // @ts-expect-error redundand checks better to wrap in this directive\n isRouteEntity(childNode.props?.route);\n\n if (isRouteChild) {\n const route = (childNode.props as any).route as AnyRoute;\n\n if (route.isOpened) {\n activeChildRouteNode = childNode;\n break;\n } else {\n if (route.isOpening) {\n hasRoutesInOpening = true;\n }\n lastInactiveChildNode = childNode;\n }\n } else {\n lastInactiveChildNode = childNode;\n }\n }\n\n const hasActiveChildNode = !!activeChildRouteNode;\n\n useEffect(() => {\n if (!hasActiveChildNode && !hasRoutesInOpening && otherwiseNavigation) {\n if (typeof otherwiseNavigation === 'string') {\n const history = routeConfig.get().history;\n const url = `${otherwiseNavigation}${buildSearchString(navigateParams.query || {})}`;\n\n if (navigateParams.replace) {\n history.replace(url, navigateParams.state);\n } else {\n history.push(url, navigateParams.state);\n }\n } else if (!otherwiseNavigation.isOpened) {\n otherwiseNavigation.open(params, navigateParams);\n }\n }\n }, [hasActiveChildNode, hasRoutesInOpening, otherwiseNavigation]);\n\n if (otherwiseNavigation && !activeChildRouteNode) {\n return null;\n }\n\n const resultNodeToRender =\n activeChildRouteNode ?? lastInactiveChildNode ?? null;\n\n if (Layout) {\n return <Layout>{resultNodeToRender}</Layout>;\n }\n\n return resultNodeToRender;\n },\n) as unknown as RouteViewGroupComponent;\n"],"names":["observer","forwardRef","useRef","isShallowEqual","useMemo","navigateParams","routeConfig","href","parseSearchString","query","buildSearchString","isValidElement","cloneElement","jsx","loadable","isRouteEntity","useEffect"],"mappings":"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"}
|
package/react.js
CHANGED
|
@@ -123,22 +123,31 @@ const RouteViewGroup = observer(
|
|
|
123
123
|
params,
|
|
124
124
|
...navigateParams
|
|
125
125
|
}) => {
|
|
126
|
-
let
|
|
126
|
+
let activeChildRouteNode = null;
|
|
127
127
|
let lastInactiveChildNode = null;
|
|
128
|
+
let hasRoutesInOpening = false;
|
|
128
129
|
const childNodes = Array.isArray(children) ? children : [children];
|
|
129
130
|
for (const childNode of childNodes) {
|
|
130
|
-
|
|
131
|
-
isRouteEntity(childNode.props?.route)
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
131
|
+
const isRouteChild = isValidElement(childNode) && // @ts-expect-error redundand checks better to wrap in this directive
|
|
132
|
+
isRouteEntity(childNode.props?.route);
|
|
133
|
+
if (isRouteChild) {
|
|
134
|
+
const route = childNode.props.route;
|
|
135
|
+
if (route.isOpened) {
|
|
136
|
+
activeChildRouteNode = childNode;
|
|
137
|
+
break;
|
|
138
|
+
} else {
|
|
139
|
+
if (route.isOpening) {
|
|
140
|
+
hasRoutesInOpening = true;
|
|
141
|
+
}
|
|
142
|
+
lastInactiveChildNode = childNode;
|
|
143
|
+
}
|
|
135
144
|
} else {
|
|
136
145
|
lastInactiveChildNode = childNode;
|
|
137
146
|
}
|
|
138
147
|
}
|
|
139
|
-
const hasActiveChildNode = !!
|
|
148
|
+
const hasActiveChildNode = !!activeChildRouteNode;
|
|
140
149
|
useEffect(() => {
|
|
141
|
-
if (!hasActiveChildNode && otherwiseNavigation) {
|
|
150
|
+
if (!hasActiveChildNode && !hasRoutesInOpening && otherwiseNavigation) {
|
|
142
151
|
if (typeof otherwiseNavigation === "string") {
|
|
143
152
|
const history = routeConfig.get().history;
|
|
144
153
|
const url = `${otherwiseNavigation}${buildSearchString(navigateParams.query || {})}`;
|
|
@@ -151,11 +160,11 @@ const RouteViewGroup = observer(
|
|
|
151
160
|
otherwiseNavigation.open(params, navigateParams);
|
|
152
161
|
}
|
|
153
162
|
}
|
|
154
|
-
}, [hasActiveChildNode, otherwiseNavigation]);
|
|
155
|
-
if (otherwiseNavigation && !
|
|
163
|
+
}, [hasActiveChildNode, hasRoutesInOpening, otherwiseNavigation]);
|
|
164
|
+
if (otherwiseNavigation && !activeChildRouteNode) {
|
|
156
165
|
return null;
|
|
157
166
|
}
|
|
158
|
-
const resultNodeToRender =
|
|
167
|
+
const resultNodeToRender = activeChildRouteNode ?? lastInactiveChildNode ?? null;
|
|
159
168
|
if (Layout) {
|
|
160
169
|
return /* @__PURE__ */ jsx(Layout, { children: resultNodeToRender });
|
|
161
170
|
}
|
package/react.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"react.js","sources":["../src/react/components/link.tsx","../src/react/components/route-view.tsx","../src/react/components/route-view-group.tsx"],"sourcesContent":["import { observer } from 'mobx-react-lite';\nimport {\n type AnyRoute,\n buildSearchString,\n type InputPathParams,\n parseSearchString,\n type RouteNavigateParams,\n routeConfig,\n} from 'mobx-route';\nimport {\n type AnchorHTMLAttributes,\n cloneElement,\n forwardRef,\n isValidElement,\n type MouseEvent,\n useMemo,\n useRef,\n} from 'react';\nimport { isShallowEqual } from 'yummies/data';\nimport type { IsPartial } from 'yummies/types';\n\ninterface LinkAnchorProps\n extends Omit<AnchorHTMLAttributes<HTMLAnchorElement>, 'href'> {\n asChild?: boolean;\n}\n\ntype LinkPathRouteProps<TRoute extends AnyRoute> = {\n to: TRoute;\n} & (IsPartial<InputPathParams<TRoute['path']>> extends true\n ? {\n params?: InputPathParams<TRoute['path']> | null | undefined;\n }\n : { params: InputPathParams<TRoute['path']> });\n\ntype LinkSimpleRouteProps =\n | {\n to: string;\n }\n | {\n href: string;\n };\n\nexport type LinkProps<TRoute extends AnyRoute> = LinkAnchorProps &\n RouteNavigateParams &\n (LinkPathRouteProps<TRoute> | LinkSimpleRouteProps);\n\ntype LinkComponentType = <TRoute extends AnyRoute>(\n props: LinkProps<TRoute>,\n) => React.ReactNode;\n\nexport const Link = observer(\n forwardRef<\n HTMLAnchorElement,\n LinkAnchorProps &\n RouteNavigateParams & {\n params?: any;\n to: string | AnyRoute;\n href: string;\n }\n >(\n (\n {\n to,\n href: outerHref,\n mergeQuery,\n asChild,\n children,\n params,\n // route navigate params\n query,\n replace,\n state,\n ...outerAnchorProps\n },\n ref,\n ) => {\n const isExternalNavigation =\n outerAnchorProps.target === '_blank' ||\n outerAnchorProps.target === 'blank';\n const queryDataRef = useRef<RouteNavigateParams['query']>(query);\n\n if (!isShallowEqual(queryDataRef.current, query)) {\n queryDataRef.current = query;\n }\n\n const { href, navigateParams } = useMemo(() => {\n const navigateParams: RouteNavigateParams = {\n mergeQuery,\n query,\n replace,\n state,\n };\n\n const cfg = routeConfig.get();\n\n let href: string;\n\n if (outerHref) {\n href = outerHref;\n } else {\n if (typeof to === 'string') {\n const isNeedToMergeQuery =\n navigateParams.mergeQuery ?? cfg.mergeQuery;\n\n const [path, ...querySegments] = to.split('?');\n\n const existedQuery = parseSearchString(querySegments.join('?'));\n\n const query = {\n ...(isNeedToMergeQuery ? cfg.queryParams.data : {}),\n ...existedQuery,\n ...navigateParams.query,\n };\n\n href = `${path}${buildSearchString(query)}`;\n } else {\n href = to.createUrl(\n params,\n navigateParams.query,\n navigateParams.mergeQuery,\n );\n }\n }\n\n return {\n href: cfg.formatLinkHref?.(href) ?? href,\n navigateParams,\n };\n }, [mergeQuery, replace, state, to, queryDataRef.current]);\n\n const handleClick = (event: MouseEvent<HTMLAnchorElement>) => {\n if (\n isExternalNavigation ||\n event.ctrlKey ||\n event.metaKey ||\n event.altKey ||\n event.shiftKey ||\n event.button !== 0\n )\n return;\n\n outerAnchorProps.onClick?.(event);\n\n if (!event.defaultPrevented) {\n event.preventDefault();\n\n if (navigateParams.replace) {\n routeConfig.get().history.replace(href, navigateParams.state);\n } else {\n routeConfig.get().history.push(href, navigateParams.state);\n }\n }\n };\n\n const anchorProps = {\n ...outerAnchorProps,\n href,\n onClick: handleClick,\n rel:\n outerAnchorProps.rel ??\n (isExternalNavigation ? 'noopener noreferrer' : undefined),\n };\n\n return asChild && isValidElement(children) ? (\n cloneElement(children, anchorProps)\n ) : (\n <a {...anchorProps} ref={ref}>\n {children}\n </a>\n );\n },\n ),\n) as unknown as LinkComponentType;\n","import { observer } from 'mobx-react-lite';\nimport type {\n AnyAbstractRouteEntity,\n AnyRoute,\n AnyVirtualRoute,\n} from 'mobx-route';\nimport { useRef } from 'react';\nimport { type LoadableConfig, loadable } from 'react-simple-loadable';\n\nexport type RouteViewComponent<TRoute extends AnyAbstractRouteEntity> =\n React.ComponentType<RouteViewProps<TRoute>>;\n\ninterface RouteViewConfigWithoutRoute {\n children?: React.ReactNode | (() => React.ReactNode);\n}\n\nexport interface RouteViewConfigWithRoute<TRoute extends AnyAbstractRouteEntity>\n extends Pick<LoadableConfig, 'loading' | 'preload' | 'throwOnError'> {\n route: TRoute;\n view?: RouteViewComponent<TRoute>;\n loadView?: (route: TRoute) => Promise<RouteViewComponent<TRoute>>;\n /**\n * Case when route is not opened\n */\n fallback?: React.ReactNode;\n children?:\n | React.ReactNode\n | ((\n params: RouteViewProps<TRoute>['params'],\n route: TRoute,\n ) => React.ReactNode);\n}\n\nexport type RouteViewConfig<TRoute extends AnyAbstractRouteEntity> =\n | RouteViewConfigWithRoute<TRoute>\n | RouteViewConfigWithoutRoute;\n\nexport type RouteViewProps<TRoute extends AnyAbstractRouteEntity> = {\n children?: React.ReactNode;\n params: TRoute extends AnyRoute\n ? Exclude<TRoute['params'], null | undefined>\n : TRoute extends AnyVirtualRoute\n ? TRoute['params']\n : never;\n};\n\ntype RouteViewBaseComponent = <TRoute extends AnyAbstractRouteEntity>(\n props: RouteViewConfig<TRoute>,\n) => React.ReactNode;\n\nfunction RouteViewBase<TRoute extends AnyAbstractRouteEntity>(\n props: Readonly<RouteViewConfig<TRoute>>,\n): React.ReactNode {\n // @ts-expect-error redundand pass first argument\n const lazyViewComponentRef = useRef<React.ComponentType<any>>();\n\n let Component: React.ComponentType<any> | undefined;\n\n if (!('route' in props)) {\n return typeof props.children === 'function'\n ? props.children()\n : props.children;\n }\n\n if (!props.route.isOpened) {\n return props.fallback ?? null;\n }\n\n if (props.loadView) {\n if (!lazyViewComponentRef.current) {\n lazyViewComponentRef.current = loadable({\n load: () => props.loadView!(props.route),\n loading: props.loading,\n preload: props.preload,\n throwOnError: props.throwOnError,\n });\n }\n Component = lazyViewComponentRef.current;\n } else {\n Component = props.view;\n }\n\n const params: any = 'params' in props.route ? props.route.params : {};\n\n if (Component) {\n return <Component params={params}>{props.children}</Component>;\n }\n\n if (typeof props.children === 'function') {\n return props.children(params, props.route);\n }\n\n return props.children;\n}\n\nexport const RouteView = observer(RouteViewBase) as RouteViewBaseComponent;\n","import { observer } from 'mobx-react-lite';\nimport {\n type AnyRouteEntity,\n buildSearchString,\n isRouteEntity,\n type RouteNavigateParams,\n type RouteParams,\n routeConfig,\n} from 'mobx-route';\nimport { isValidElement, useEffect } from 'react';\nimport type { IsPartial, Maybe } from 'yummies/types';\n\ntype LayoutComponent =\n | React.ComponentType<{ children?: React.ReactNode }>\n | React.ComponentType<{ children: React.ReactNode }>;\n\ninterface BaseProps extends RouteNavigateParams {\n children: React.ReactNode;\n layout?: LayoutComponent;\n}\n\ntype PropsWithDefaultRoute<TRoute extends AnyRouteEntity> = BaseProps & {\n otherwise?: TRoute;\n} & (IsPartial<RouteParams<TRoute>> extends true\n ? {\n params?: Maybe<RouteParams<TRoute>>;\n }\n : {\n params: RouteParams<TRoute>;\n });\n\ntype PropsWithDefaultUrl = BaseProps & {\n otherwise?: string;\n};\n\nexport type RouteViewGroupProps<TRoute extends AnyRouteEntity> =\n | PropsWithDefaultRoute<TRoute>\n | PropsWithDefaultUrl;\n\ntype RouteViewGroupComponent = <TRoute extends AnyRouteEntity>(\n props: RouteViewGroupProps<TRoute>,\n) => React.ReactNode;\n\nexport const RouteViewGroup = observer(\n <TRoute extends AnyRouteEntity>({\n children,\n layout: Layout,\n otherwise: otherwiseNavigation,\n // @ts-expect-error\n params,\n ...navigateParams\n }: RouteViewGroupProps<TRoute>) => {\n let activeChildNode: React.ReactNode = null;\n let lastInactiveChildNode: React.ReactNode = null;\n\n const childNodes: React.ReactNode[] = Array.isArray(children)\n ? children\n : [children];\n\n for (const childNode of childNodes) {\n if (\n isValidElement(childNode) &&\n // @ts-expect-error redundand checks better to wrap in this directive\n isRouteEntity(childNode.props?.route) &&\n // @ts-expect-error redundand checks better to wrap in this directive\n childNode.props.route.isOpened\n ) {\n activeChildNode = childNode;\n break;\n } else {\n lastInactiveChildNode = childNode;\n }\n }\n\n const hasActiveChildNode = !!activeChildNode;\n\n useEffect(() => {\n if (!hasActiveChildNode && otherwiseNavigation) {\n if (typeof otherwiseNavigation === 'string') {\n const history = routeConfig.get().history;\n const url = `${otherwiseNavigation}${buildSearchString(navigateParams.query || {})}`;\n\n if (navigateParams.replace) {\n history.replace(url, navigateParams.state);\n } else {\n history.push(url, navigateParams.state);\n }\n } else if (!otherwiseNavigation.isOpened) {\n otherwiseNavigation.open(params, navigateParams);\n }\n }\n }, [hasActiveChildNode, otherwiseNavigation]);\n\n if (otherwiseNavigation && !activeChildNode) {\n return null;\n }\n\n const resultNodeToRender = activeChildNode ?? lastInactiveChildNode ?? null;\n\n if (Layout) {\n return <Layout>{resultNodeToRender}</Layout>;\n }\n\n return resultNodeToRender;\n },\n) as unknown as RouteViewGroupComponent;\n"],"names":["navigateParams","href","query"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"react.js","sources":["../src/react/components/link.tsx","../src/react/components/route-view.tsx","../src/react/components/route-view-group.tsx"],"sourcesContent":["import { observer } from 'mobx-react-lite';\nimport {\n type AnyRoute,\n buildSearchString,\n type InputPathParams,\n parseSearchString,\n type RouteNavigateParams,\n routeConfig,\n} from 'mobx-route';\nimport {\n type AnchorHTMLAttributes,\n cloneElement,\n forwardRef,\n isValidElement,\n type MouseEvent,\n useMemo,\n useRef,\n} from 'react';\nimport { isShallowEqual } from 'yummies/data';\nimport type { IsPartial } from 'yummies/types';\n\ninterface LinkAnchorProps\n extends Omit<AnchorHTMLAttributes<HTMLAnchorElement>, 'href'> {\n asChild?: boolean;\n}\n\ntype LinkPathRouteProps<TRoute extends AnyRoute> = {\n to: TRoute;\n} & (IsPartial<InputPathParams<TRoute['path']>> extends true\n ? {\n params?: InputPathParams<TRoute['path']> | null | undefined;\n }\n : { params: InputPathParams<TRoute['path']> });\n\ntype LinkSimpleRouteProps =\n | {\n to: string;\n }\n | {\n href: string;\n };\n\nexport type LinkProps<TRoute extends AnyRoute> = LinkAnchorProps &\n RouteNavigateParams &\n (LinkPathRouteProps<TRoute> | LinkSimpleRouteProps);\n\ntype LinkComponentType = <TRoute extends AnyRoute>(\n props: LinkProps<TRoute>,\n) => React.ReactNode;\n\nexport const Link = observer(\n forwardRef<\n HTMLAnchorElement,\n LinkAnchorProps &\n RouteNavigateParams & {\n params?: any;\n to: string | AnyRoute;\n href: string;\n }\n >(\n (\n {\n to,\n href: outerHref,\n mergeQuery,\n asChild,\n children,\n params,\n // route navigate params\n query,\n replace,\n state,\n ...outerAnchorProps\n },\n ref,\n ) => {\n const isExternalNavigation =\n outerAnchorProps.target === '_blank' ||\n outerAnchorProps.target === 'blank';\n const queryDataRef = useRef<RouteNavigateParams['query']>(query);\n\n if (!isShallowEqual(queryDataRef.current, query)) {\n queryDataRef.current = query;\n }\n\n const { href, navigateParams } = useMemo(() => {\n const navigateParams: RouteNavigateParams = {\n mergeQuery,\n query,\n replace,\n state,\n };\n\n const cfg = routeConfig.get();\n\n let href: string;\n\n if (outerHref) {\n href = outerHref;\n } else {\n if (typeof to === 'string') {\n const isNeedToMergeQuery =\n navigateParams.mergeQuery ?? cfg.mergeQuery;\n\n const [path, ...querySegments] = to.split('?');\n\n const existedQuery = parseSearchString(querySegments.join('?'));\n\n const query = {\n ...(isNeedToMergeQuery ? cfg.queryParams.data : {}),\n ...existedQuery,\n ...navigateParams.query,\n };\n\n href = `${path}${buildSearchString(query)}`;\n } else {\n href = to.createUrl(\n params,\n navigateParams.query,\n navigateParams.mergeQuery,\n );\n }\n }\n\n return {\n href: cfg.formatLinkHref?.(href) ?? href,\n navigateParams,\n };\n }, [mergeQuery, replace, state, to, queryDataRef.current]);\n\n const handleClick = (event: MouseEvent<HTMLAnchorElement>) => {\n if (\n isExternalNavigation ||\n event.ctrlKey ||\n event.metaKey ||\n event.altKey ||\n event.shiftKey ||\n event.button !== 0\n )\n return;\n\n outerAnchorProps.onClick?.(event);\n\n if (!event.defaultPrevented) {\n event.preventDefault();\n\n if (navigateParams.replace) {\n routeConfig.get().history.replace(href, navigateParams.state);\n } else {\n routeConfig.get().history.push(href, navigateParams.state);\n }\n }\n };\n\n const anchorProps = {\n ...outerAnchorProps,\n href,\n onClick: handleClick,\n rel:\n outerAnchorProps.rel ??\n (isExternalNavigation ? 'noopener noreferrer' : undefined),\n };\n\n return asChild && isValidElement(children) ? (\n cloneElement(children, anchorProps)\n ) : (\n <a {...anchorProps} ref={ref}>\n {children}\n </a>\n );\n },\n ),\n) as unknown as LinkComponentType;\n","import { observer } from 'mobx-react-lite';\nimport type {\n AnyAbstractRouteEntity,\n AnyRoute,\n AnyVirtualRoute,\n} from 'mobx-route';\nimport { useRef } from 'react';\nimport { type LoadableConfig, loadable } from 'react-simple-loadable';\n\nexport type RouteViewComponent<TRoute extends AnyAbstractRouteEntity> =\n React.ComponentType<RouteViewProps<TRoute>>;\n\ninterface RouteViewConfigWithoutRoute {\n children?: React.ReactNode | (() => React.ReactNode);\n}\n\nexport interface RouteViewConfigWithRoute<TRoute extends AnyAbstractRouteEntity>\n extends Pick<LoadableConfig, 'loading' | 'preload' | 'throwOnError'> {\n route: TRoute;\n view?: RouteViewComponent<TRoute>;\n loadView?: (route: TRoute) => Promise<RouteViewComponent<TRoute>>;\n /**\n * Case when route is not opened\n */\n fallback?: React.ReactNode;\n children?:\n | React.ReactNode\n | ((\n params: RouteViewProps<TRoute>['params'],\n route: TRoute,\n ) => React.ReactNode);\n}\n\nexport type RouteViewConfig<TRoute extends AnyAbstractRouteEntity> =\n | RouteViewConfigWithRoute<TRoute>\n | RouteViewConfigWithoutRoute;\n\nexport type RouteViewProps<TRoute extends AnyAbstractRouteEntity> = {\n children?: React.ReactNode;\n params: TRoute extends AnyRoute\n ? Exclude<TRoute['params'], null | undefined>\n : TRoute extends AnyVirtualRoute\n ? TRoute['params']\n : never;\n};\n\ntype RouteViewBaseComponent = <TRoute extends AnyAbstractRouteEntity>(\n props: RouteViewConfig<TRoute>,\n) => React.ReactNode;\n\nfunction RouteViewBase<TRoute extends AnyAbstractRouteEntity>(\n props: Readonly<RouteViewConfig<TRoute>>,\n): React.ReactNode {\n // @ts-expect-error redundand pass first argument\n const lazyViewComponentRef = useRef<React.ComponentType<any>>();\n\n let Component: React.ComponentType<any> | undefined;\n\n if (!('route' in props)) {\n return typeof props.children === 'function'\n ? props.children()\n : props.children;\n }\n\n if (!props.route.isOpened) {\n return props.fallback ?? null;\n }\n\n if (props.loadView) {\n if (!lazyViewComponentRef.current) {\n lazyViewComponentRef.current = loadable({\n load: () => props.loadView!(props.route),\n loading: props.loading,\n preload: props.preload,\n throwOnError: props.throwOnError,\n });\n }\n Component = lazyViewComponentRef.current;\n } else {\n Component = props.view;\n }\n\n const params: any = 'params' in props.route ? props.route.params : {};\n\n if (Component) {\n return <Component params={params}>{props.children}</Component>;\n }\n\n if (typeof props.children === 'function') {\n return props.children(params, props.route);\n }\n\n return props.children;\n}\n\nexport const RouteView = observer(RouteViewBase) as RouteViewBaseComponent;\n","import { observer } from 'mobx-react-lite';\nimport {\n type AnyRoute,\n type AnyRouteEntity,\n buildSearchString,\n isRouteEntity,\n type RouteNavigateParams,\n type RouteParams,\n routeConfig,\n} from 'mobx-route';\nimport { isValidElement, useEffect } from 'react';\nimport type { IsPartial, Maybe } from 'yummies/types';\n\ntype LayoutComponent =\n | React.ComponentType<{ children?: React.ReactNode }>\n | React.ComponentType<{ children: React.ReactNode }>;\n\ninterface BaseProps extends RouteNavigateParams {\n children: React.ReactNode;\n layout?: LayoutComponent;\n}\n\ntype PropsWithDefaultRoute<TRoute extends AnyRouteEntity> = BaseProps & {\n otherwise?: TRoute;\n} & (IsPartial<RouteParams<TRoute>> extends true\n ? {\n params?: Maybe<RouteParams<TRoute>>;\n }\n : {\n params: RouteParams<TRoute>;\n });\n\ntype PropsWithDefaultUrl = BaseProps & {\n otherwise?: string;\n};\n\nexport type RouteViewGroupProps<TRoute extends AnyRouteEntity> =\n | PropsWithDefaultRoute<TRoute>\n | PropsWithDefaultUrl;\n\ntype RouteViewGroupComponent = <TRoute extends AnyRouteEntity>(\n props: RouteViewGroupProps<TRoute>,\n) => React.ReactNode;\n\nexport const RouteViewGroup = observer(\n <TRoute extends AnyRouteEntity>({\n children,\n layout: Layout,\n otherwise: otherwiseNavigation,\n // @ts-expect-error\n params,\n ...navigateParams\n }: RouteViewGroupProps<TRoute>) => {\n let activeChildRouteNode: React.ReactNode = null;\n let lastInactiveChildNode: React.ReactNode = null;\n let hasRoutesInOpening = false;\n\n const childNodes: React.ReactNode[] = Array.isArray(children)\n ? children\n : [children];\n\n for (const childNode of childNodes) {\n const isRouteChild =\n isValidElement(childNode) &&\n // @ts-expect-error redundand checks better to wrap in this directive\n isRouteEntity(childNode.props?.route);\n\n if (isRouteChild) {\n const route = (childNode.props as any).route as AnyRoute;\n\n if (route.isOpened) {\n activeChildRouteNode = childNode;\n break;\n } else {\n if (route.isOpening) {\n hasRoutesInOpening = true;\n }\n lastInactiveChildNode = childNode;\n }\n } else {\n lastInactiveChildNode = childNode;\n }\n }\n\n const hasActiveChildNode = !!activeChildRouteNode;\n\n useEffect(() => {\n if (!hasActiveChildNode && !hasRoutesInOpening && otherwiseNavigation) {\n if (typeof otherwiseNavigation === 'string') {\n const history = routeConfig.get().history;\n const url = `${otherwiseNavigation}${buildSearchString(navigateParams.query || {})}`;\n\n if (navigateParams.replace) {\n history.replace(url, navigateParams.state);\n } else {\n history.push(url, navigateParams.state);\n }\n } else if (!otherwiseNavigation.isOpened) {\n otherwiseNavigation.open(params, navigateParams);\n }\n }\n }, [hasActiveChildNode, hasRoutesInOpening, otherwiseNavigation]);\n\n if (otherwiseNavigation && !activeChildRouteNode) {\n return null;\n }\n\n const resultNodeToRender =\n activeChildRouteNode ?? lastInactiveChildNode ?? null;\n\n if (Layout) {\n return <Layout>{resultNodeToRender}</Layout>;\n }\n\n return resultNodeToRender;\n },\n) as unknown as RouteViewGroupComponent;\n"],"names":["navigateParams","href","query"],"mappings":"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"}
|