@codeleap/web-navigation 6.2.3 → 6.8.0
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/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/navigation.d.ts +80 -0
- package/dist/navigation.d.ts.map +1 -0
- package/dist/types.d.ts +80 -0
- package/dist/types.d.ts.map +1 -0
- package/package.json +18 -4
- package/src/navigation.tsx +31 -10
- package/src/types.ts +47 -0
- package/package.json.bak +0 -21
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,cAAc,CAAA"}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { Config, History, Navigator, RouteParams, RoutePath, Routes } from './types';
|
|
2
|
+
export type { Navigator, Routes, };
|
|
3
|
+
/**
|
|
4
|
+
* Type-safe navigation controller that wraps a platform-specific navigator
|
|
5
|
+
* (e.g. Next.js `router.push`) and enforces route param contracts at compile time.
|
|
6
|
+
*
|
|
7
|
+
* `R` is the routes definition object — nested keys map to `{{param}}`-bearing
|
|
8
|
+
* path strings. `O` is the navigator's option bag. `C` is the shared context
|
|
9
|
+
* forwarded to every navigator call so adapters can read app-level state without
|
|
10
|
+
* closure coupling.
|
|
11
|
+
*
|
|
12
|
+
* The class is SSR-safe: any method that touches `window` or `history` short-circuits
|
|
13
|
+
* when running outside a browser environment.
|
|
14
|
+
*/
|
|
15
|
+
export declare class Navigation<O extends object, R extends object = {}, C extends Record<string, any> = {}> {
|
|
16
|
+
private _history;
|
|
17
|
+
private config;
|
|
18
|
+
get history(): History;
|
|
19
|
+
context: C;
|
|
20
|
+
private putHistory;
|
|
21
|
+
private merge;
|
|
22
|
+
private navigator;
|
|
23
|
+
private routes;
|
|
24
|
+
/**
|
|
25
|
+
* @param routes Nested object whose leaf values are path strings with optional
|
|
26
|
+
* `{{param}}` placeholders. Dot-notation keys derived from this object become
|
|
27
|
+
* the typed route identifiers accepted by `navigate`, `getPath`, etc.
|
|
28
|
+
* @param navigator Platform adapter called for every navigation; receives the
|
|
29
|
+
* resolved path, stripped options, and the current `context` value.
|
|
30
|
+
* @param config Optional behaviour flags. Merged with defaults, so partial
|
|
31
|
+
* configs are safe.
|
|
32
|
+
*/
|
|
33
|
+
constructor(routes: R, navigator: Navigator<O, C>, config?: Config);
|
|
34
|
+
/**
|
|
35
|
+
* Checks if the user is on a certain route based on the parameters passed
|
|
36
|
+
* @param route Route that will be used to direct
|
|
37
|
+
* @param routeParams Parameters that will be applied to the route
|
|
38
|
+
* @param exact Accurate path checking - default false
|
|
39
|
+
* @returns Is on the route - boolean
|
|
40
|
+
*/
|
|
41
|
+
isCurrentRoute<T extends keyof Routes<R>>(route: T, routeParams?: Record<Routes<R>[T], string | number>, exact?: boolean): boolean;
|
|
42
|
+
/**
|
|
43
|
+
* Get the path from the route
|
|
44
|
+
* @param route Route that will be used to direct
|
|
45
|
+
* @returns Path - string
|
|
46
|
+
*/
|
|
47
|
+
getPath(route: keyof Routes<R>): string;
|
|
48
|
+
/**
|
|
49
|
+
* Get the path from the route and route params
|
|
50
|
+
* @param route Route that will be used to direct
|
|
51
|
+
* @param routeParams Parameters that will be applied to the route
|
|
52
|
+
* @returns Path - string
|
|
53
|
+
*/
|
|
54
|
+
getPathWithParams<T extends keyof Routes<R>>(route: T, routeParams?: Record<Routes<R>[T], string | number>): string;
|
|
55
|
+
/**
|
|
56
|
+
* Function to navigate to the previous page, if history is enabled, the penultimate record will be used,
|
|
57
|
+
* otherwise the browser's own api with "history.back()"
|
|
58
|
+
*/
|
|
59
|
+
goBack(): void;
|
|
60
|
+
/**
|
|
61
|
+
* Main function to navigate between the app using the route system with dynamic parameters
|
|
62
|
+
* @param route Route that will be used to direct
|
|
63
|
+
* @param options Route parameters (marked by {{}}), which will be automatically shown if they exist, and navigator options and route queryParams can also be passed through the "params" property
|
|
64
|
+
*/
|
|
65
|
+
navigate<T extends keyof Routes<R>>(route: T, options?: Record<Routes<R>[T], string | number> & O & {
|
|
66
|
+
params?: RouteParams;
|
|
67
|
+
}): void;
|
|
68
|
+
/**
|
|
69
|
+
* Calls the navigator to direct the user to a page
|
|
70
|
+
* @param path Path to which the user will be taken
|
|
71
|
+
* @param options Options that will be passed to the navigator
|
|
72
|
+
* @param info Information that will be added to the history
|
|
73
|
+
*/
|
|
74
|
+
to(path: RoutePath, options?: O, info?: {}): void;
|
|
75
|
+
/**
|
|
76
|
+
* Clear history data
|
|
77
|
+
*/
|
|
78
|
+
wipeHistory(): void;
|
|
79
|
+
}
|
|
80
|
+
//# sourceMappingURL=navigation.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"navigation.d.ts","sourceRoot":"","sources":["../src/navigation.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAY,MAAM,EAAE,OAAO,EAAE,SAAS,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,SAAS,CAAA;AAU9F,YAAY,EACV,SAAS,EACT,MAAM,GACP,CAAA;AAED;;;;;;;;;;;GAWG;AACH,qBAAa,UAAU,CAAC,CAAC,SAAS,MAAM,EAAE,CAAC,SAAS,MAAM,GAAG,EAAE,EAAE,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,EAAE;IACjG,OAAO,CAAC,QAAQ,CAAc;IAE9B,OAAO,CAAC,MAAM,CAAwB;IAEtC,IAAI,OAAO,YAEV;IAEM,OAAO,EAAE,CAAC,CAAU;IAE3B,OAAO,CAAC,UAAU;IAkBlB,OAAO,CAAC,KAAK;IAOb,OAAO,CAAC,SAAS,CAAgD;IAEjE,OAAO,CAAC,MAAM,CAAa;IAE3B;;;;;;;;OAQG;gBAED,MAAM,EAAE,CAAC,EACT,SAAS,EAAE,SAAS,CAAC,CAAC,EAAE,CAAC,CAAC,EAC1B,MAAM,GAAE,MAAW;IAOrB;;;;;;OAMG;IACI,cAAc,CAAC,CAAC,SAAS,MAAM,MAAM,CAAC,CAAC,CAAC,EAC7C,KAAK,EAAE,CAAC,EAER,WAAW,GAAE,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAAa,EAC9D,KAAK,UAAQ;IA+Bf;;;;OAIG;IACI,OAAO,CAAC,KAAK,EAAE,MAAM,MAAM,CAAC,CAAC,CAAC,GAAG,MAAM;IAmB9C;;;;;OAKG;IACI,iBAAiB,CAAC,CAAC,SAAS,MAAM,MAAM,CAAC,CAAC,CAAC,EAChD,KAAK,EAAE,CAAC,EAER,WAAW,GAAE,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAAa;IAyBhE;;;OAGG;IACI,MAAM;IAuBb;;;;OAIG;IACI,QAAQ,CAAC,CAAC,SAAS,MAAM,MAAM,CAAC,CAAC,CAAC,EACvC,KAAK,EAAE,CAAC,EAER,OAAO,GAAE,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC,GAAG,CAAC,GAAG;QAAE,MAAM,CAAC,EAAE,WAAW,CAAA;KAAc;IA6D3F;;;;;OAKG;IACI,EAAE,CAAC,IAAI,EAAE,SAAS,EAAE,OAAO,GAAE,CAAwB,EAAE,IAAI,KAAK;IAQvE;;OAEG;IACI,WAAW;CAGnB"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Recursively extracts the names of all `{{param}}` placeholders from a route
|
|
3
|
+
* string literal as a union of string literal types.
|
|
4
|
+
*
|
|
5
|
+
* Returns `never` when the string contains no placeholders, making it safe to
|
|
6
|
+
* use as a constraint — a route with no params produces an empty `Record<never, …>`.
|
|
7
|
+
*/
|
|
8
|
+
export type ExtractParams<T extends string> = T extends `${infer _Start}{{${infer Param}}}${infer Rest}` ? Param | ExtractParams<Rest> : never;
|
|
9
|
+
type Params<T> = {
|
|
10
|
+
[K in keyof T]: T[K] extends string ? ExtractParams<T[K]> : Params<T[K]>;
|
|
11
|
+
};
|
|
12
|
+
type ExtractRoutes<T, PM, Prefix extends string = ''> = {
|
|
13
|
+
[K in keyof T & string]: T[K] extends string ? {
|
|
14
|
+
[P in `${Prefix}${Prefix extends '' ? '' : '.'}${K}`]: PM[K];
|
|
15
|
+
} : ExtractRoutes<T[K], PM[K], `${Prefix}${Prefix extends '' ? '' : '.'}${K}`>;
|
|
16
|
+
}[keyof T];
|
|
17
|
+
type UnionToIntersection<U> = (U extends any ? (x: U) => void : never) extends ((x: infer I) => void) ? I : never;
|
|
18
|
+
/**
|
|
19
|
+
* Flattens a nested route definition object into a single map of dot-separated
|
|
20
|
+
* route keys → union of their `{{param}}` placeholder names.
|
|
21
|
+
*
|
|
22
|
+
* The resulting intersection type is what `Navigation` uses to enforce that
|
|
23
|
+
* every call to `navigate` or `isCurrentRoute` supplies exactly the params
|
|
24
|
+
* declared in the corresponding route string — no more, no fewer.
|
|
25
|
+
*/
|
|
26
|
+
export type Routes<T> = UnionToIntersection<ExtractRoutes<T, Params<T>>>;
|
|
27
|
+
/** An unresolved URL pathname string, before param substitution. */
|
|
28
|
+
export type RoutePath = string;
|
|
29
|
+
/** A map of query-string or URL segment key–value pairs, both typed as `string`. */
|
|
30
|
+
export type RouteParams = {
|
|
31
|
+
[x: string]: string;
|
|
32
|
+
};
|
|
33
|
+
/**
|
|
34
|
+
* The function signature every platform-specific navigator adapter must satisfy.
|
|
35
|
+
*
|
|
36
|
+
* `O` carries platform options (e.g. Next.js router options, `replace` flag).
|
|
37
|
+
* `C` is the shared context object set on `Navigation.context`; pass it through
|
|
38
|
+
* to give the adapter access to auth state, locale, etc. without coupling the
|
|
39
|
+
* types to a specific app.
|
|
40
|
+
*/
|
|
41
|
+
export type Navigator<O extends object = {}, C extends Record<string, any> = {}> = (path: RoutePath, options: O, context?: C) => void;
|
|
42
|
+
/** Escape hatch for untyped key–value bags used internally during deep-merge operations. */
|
|
43
|
+
export type AnyValue = {
|
|
44
|
+
[key: string]: any;
|
|
45
|
+
};
|
|
46
|
+
/**
|
|
47
|
+
* A single entry appended to the internal navigation history.
|
|
48
|
+
*
|
|
49
|
+
* `origin` is `null` in SSR environments where `window` is unavailable.
|
|
50
|
+
* `metadata` is whatever `Config.getMetadata()` returns at the moment of
|
|
51
|
+
* navigation — use this to capture auth state, feature flags, etc.
|
|
52
|
+
* `info` is the merged options + caller-supplied info blob stored for `goBack`.
|
|
53
|
+
*/
|
|
54
|
+
export type HistoryData = {
|
|
55
|
+
origin: string;
|
|
56
|
+
date: Date;
|
|
57
|
+
path: RoutePath;
|
|
58
|
+
metadata: any;
|
|
59
|
+
info: any;
|
|
60
|
+
};
|
|
61
|
+
/**
|
|
62
|
+
* Indexed map of history entries keyed by insertion order (1-based).
|
|
63
|
+
* Only populated when `Config.historyEnabled` is `true`.
|
|
64
|
+
*/
|
|
65
|
+
export type History = Record<number, HistoryData>;
|
|
66
|
+
export type Config = {
|
|
67
|
+
/**
|
|
68
|
+
* When `true`, every call to `Navigation.to` appends an entry to the internal
|
|
69
|
+
* history log and `goBack` uses that log instead of `window.history.back()`.
|
|
70
|
+
* Defaults to `false`.
|
|
71
|
+
*/
|
|
72
|
+
historyEnabled?: boolean;
|
|
73
|
+
/**
|
|
74
|
+
* Called at navigation time to capture a snapshot of arbitrary app state
|
|
75
|
+
* (e.g. current user, locale). The return value is stored in `HistoryData.metadata`.
|
|
76
|
+
*/
|
|
77
|
+
getMetadata?: () => any;
|
|
78
|
+
};
|
|
79
|
+
export {};
|
|
80
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,MAAM,MAAM,aAAa,CAAC,CAAC,SAAS,MAAM,IACxC,CAAC,SAAS,GAAG,MAAM,MAAM,KAAK,MAAM,KAAK,KAAK,MAAM,IAAI,EAAE,GACxD,KAAK,GAAG,aAAa,CAAC,IAAI,CAAC,GAC3B,KAAK,CAAA;AAET,KAAK,MAAM,CAAC,CAAC,IAAI;KACd,CAAC,IAAI,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS,MAAM,GAAG,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;CACzE,CAAA;AAGD,KAAK,aAAa,CAAC,CAAC,EAAE,EAAE,EAAE,MAAM,SAAS,MAAM,GAAG,EAAE,IAAI;KACrD,CAAC,IAAI,MAAM,CAAC,GAAG,MAAM,GACtB,CAAC,CAAC,CAAC,CAAC,SAAS,MAAM,GACjB;SAEC,CAAC,IAAI,GAAG,MAAM,GAAG,MAAM,SAAS,EAAE,GAAG,EAAE,GAAG,GAAG,GAAG,CAAC,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC;KAC7D,GACC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,GAAG,MAAM,GAAG,MAAM,SAAS,EAAE,GAAG,EAAE,GAAG,GAAG,GAAG,CAAC,EAAE,CAAC;CAC7E,CAAC,MAAM,CAAC,CAAC,CAAA;AAEV,KAAK,mBAAmB,CAAC,CAAC,IACxB,CAAC,CAAC,SAAS,GAAG,GAAG,CAAC,CAAC,EAAE,CAAC,KAAK,IAAI,GAAG,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC,KAAK,IAAI,CAAC,GAAG,CAAC,GAAG,KAAK,CAAA;AAErF;;;;;;;GAOG;AACH,MAAM,MAAM,MAAM,CAAC,CAAC,IAAI,mBAAmB,CAAC,aAAa,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAA;AAIxE,oEAAoE;AACpE,MAAM,MAAM,SAAS,GAAG,MAAM,CAAA;AAE9B,oFAAoF;AACpF,MAAM,MAAM,WAAW,GAAG;IACxB,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAAA;CACpB,CAAA;AAED;;;;;;;GAOG;AACH,MAAM,MAAM,SAAS,CAAC,CAAC,SAAS,MAAM,GAAG,EAAE,EAAE,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,EAAE,IAAI,CAAC,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,CAAC,EAAE,OAAO,CAAC,EAAE,CAAC,KAAK,IAAI,CAAA;AAErI,4FAA4F;AAC5F,MAAM,MAAM,QAAQ,GAAG;IACrB,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAA;CACnB,CAAA;AAED;;;;;;;GAOG;AACH,MAAM,MAAM,WAAW,GAAG;IACxB,MAAM,EAAE,MAAM,CAAA;IACd,IAAI,EAAE,IAAI,CAAA;IACV,IAAI,EAAE,SAAS,CAAA;IACf,QAAQ,EAAE,GAAG,CAAA;IACb,IAAI,EAAE,GAAG,CAAA;CACV,CAAA;AAED;;;GAGG;AACH,MAAM,MAAM,OAAO,GAAG,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAAA;AAEjD,MAAM,MAAM,MAAM,GAAG;IACnB;;;;OAIG;IACH,cAAc,CAAC,EAAE,OAAO,CAAA;IACxB;;;OAGG;IACH,WAAW,CAAC,EAAE,MAAM,GAAG,CAAA;CACxB,CAAA"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,20 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@codeleap/web-navigation",
|
|
3
|
-
"version": "6.
|
|
3
|
+
"version": "6.8.0",
|
|
4
4
|
"main": "src/index.ts",
|
|
5
|
+
"types": "dist/index.d.ts",
|
|
6
|
+
"exports": {
|
|
7
|
+
".": {
|
|
8
|
+
"source": "./src/index.ts",
|
|
9
|
+
"types": "./dist/index.d.ts",
|
|
10
|
+
"import": "./dist/index.js",
|
|
11
|
+
"default": "./dist/index.js"
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
"files": [
|
|
15
|
+
"dist",
|
|
16
|
+
"src"
|
|
17
|
+
],
|
|
5
18
|
"license": "UNLICENSED",
|
|
6
19
|
"repository": {
|
|
7
20
|
"url": "https://github.com/codeleap-uk/internal-libs-monorepo.git",
|
|
@@ -12,10 +25,11 @@
|
|
|
12
25
|
"ts-node-dev": "1.1.8"
|
|
13
26
|
},
|
|
14
27
|
"scripts": {
|
|
15
|
-
"build": "
|
|
28
|
+
"build": "tsc --build tsconfig.build.json",
|
|
29
|
+
"typecheck": "bun tsc --noEmit -p ./tsconfig.json"
|
|
16
30
|
},
|
|
17
31
|
"peerDependencies": {
|
|
18
|
-
"typescript": "
|
|
32
|
+
"typescript": "6.0.3",
|
|
19
33
|
"@fastify/deepmerge": "3.1.0"
|
|
20
34
|
}
|
|
21
|
-
}
|
|
35
|
+
}
|
package/src/navigation.tsx
CHANGED
|
@@ -13,6 +13,18 @@ export type {
|
|
|
13
13
|
Routes,
|
|
14
14
|
}
|
|
15
15
|
|
|
16
|
+
/**
|
|
17
|
+
* Type-safe navigation controller that wraps a platform-specific navigator
|
|
18
|
+
* (e.g. Next.js `router.push`) and enforces route param contracts at compile time.
|
|
19
|
+
*
|
|
20
|
+
* `R` is the routes definition object — nested keys map to `{{param}}`-bearing
|
|
21
|
+
* path strings. `O` is the navigator's option bag. `C` is the shared context
|
|
22
|
+
* forwarded to every navigator call so adapters can read app-level state without
|
|
23
|
+
* closure coupling.
|
|
24
|
+
*
|
|
25
|
+
* The class is SSR-safe: any method that touches `window` or `history` short-circuits
|
|
26
|
+
* when running outside a browser environment.
|
|
27
|
+
*/
|
|
16
28
|
export class Navigation<O extends object, R extends object = {}, C extends Record<string, any> = {}> {
|
|
17
29
|
private _history: History = {}
|
|
18
30
|
|
|
@@ -29,7 +41,7 @@ export class Navigation<O extends object, R extends object = {}, C extends Recor
|
|
|
29
41
|
|
|
30
42
|
const origin = IS_SSR ? null : window?.location?.origin
|
|
31
43
|
|
|
32
|
-
const value
|
|
44
|
+
const value = {
|
|
33
45
|
[idx]: {
|
|
34
46
|
origin,
|
|
35
47
|
date: new Date(),
|
|
@@ -37,7 +49,7 @@ export class Navigation<O extends object, R extends object = {}, C extends Recor
|
|
|
37
49
|
metadata: this.config?.getMetadata?.(),
|
|
38
50
|
info,
|
|
39
51
|
},
|
|
40
|
-
}
|
|
52
|
+
} as unknown as History
|
|
41
53
|
|
|
42
54
|
this._history = this.merge(this._history, value)
|
|
43
55
|
}
|
|
@@ -49,16 +61,25 @@ export class Navigation<O extends object, R extends object = {}, C extends Recor
|
|
|
49
61
|
)
|
|
50
62
|
}
|
|
51
63
|
|
|
52
|
-
private navigator: Navigator<O> = null
|
|
64
|
+
private navigator: Navigator<O> = null as unknown as Navigator<O>
|
|
53
65
|
|
|
54
66
|
private routes: R = {} as R
|
|
55
67
|
|
|
68
|
+
/**
|
|
69
|
+
* @param routes Nested object whose leaf values are path strings with optional
|
|
70
|
+
* `{{param}}` placeholders. Dot-notation keys derived from this object become
|
|
71
|
+
* the typed route identifiers accepted by `navigate`, `getPath`, etc.
|
|
72
|
+
* @param navigator Platform adapter called for every navigation; receives the
|
|
73
|
+
* resolved path, stripped options, and the current `context` value.
|
|
74
|
+
* @param config Optional behaviour flags. Merged with defaults, so partial
|
|
75
|
+
* configs are safe.
|
|
76
|
+
*/
|
|
56
77
|
constructor(
|
|
57
78
|
routes: R,
|
|
58
79
|
navigator: Navigator<O, C>,
|
|
59
80
|
config: Config = {},
|
|
60
81
|
) {
|
|
61
|
-
this.navigator = navigator
|
|
82
|
+
this.navigator = navigator as unknown as Navigator<O>
|
|
62
83
|
this.routes = routes
|
|
63
84
|
this.config = this.merge(this.config, config)
|
|
64
85
|
}
|
|
@@ -119,7 +140,7 @@ export class Navigation<O extends object, R extends object = {}, C extends Recor
|
|
|
119
140
|
const indexesAccess = route?.split('.')
|
|
120
141
|
|
|
121
142
|
for (const index of indexesAccess) {
|
|
122
|
-
path = path?.[index]
|
|
143
|
+
path = (path as Record<string, any>)?.[index]
|
|
123
144
|
}
|
|
124
145
|
} else {
|
|
125
146
|
// @ts-ignore
|
|
@@ -143,7 +164,7 @@ export class Navigation<O extends object, R extends object = {}, C extends Recor
|
|
|
143
164
|
let path = this.getPath(route)
|
|
144
165
|
|
|
145
166
|
for (const key in routeParams) {
|
|
146
|
-
const value = String(routeParams?.[key])
|
|
167
|
+
const value = String((routeParams as Record<string, any>)?.[key])
|
|
147
168
|
|
|
148
169
|
const searchPartial = `{{${key}}}`
|
|
149
170
|
|
|
@@ -210,7 +231,7 @@ export class Navigation<O extends object, R extends object = {}, C extends Recor
|
|
|
210
231
|
const queryParamsKey = 'params'
|
|
211
232
|
|
|
212
233
|
for (const key in options) {
|
|
213
|
-
const value = options?.[key]
|
|
234
|
+
const value = (options as Record<string, any>)?.[key]
|
|
214
235
|
|
|
215
236
|
const searchPartial = `{{${key}}}`
|
|
216
237
|
|
|
@@ -230,12 +251,12 @@ export class Navigation<O extends object, R extends object = {}, C extends Recor
|
|
|
230
251
|
}
|
|
231
252
|
|
|
232
253
|
if (typeof params === 'object') {
|
|
233
|
-
let searchParams = null
|
|
254
|
+
let searchParams: string | null = null
|
|
234
255
|
|
|
235
256
|
for (const paramKey in (params ?? {})) {
|
|
236
257
|
const value = params?.[paramKey]
|
|
237
258
|
const param = `${paramKey}=${encodeURIComponent(value)}`
|
|
238
|
-
const separator = searchParams == null ? '' : '&'
|
|
259
|
+
const separator: string = searchParams == null ? '' : '&'
|
|
239
260
|
|
|
240
261
|
searchParams = `${searchParams ?? ''}${separator}${param}`
|
|
241
262
|
}
|
|
@@ -265,7 +286,7 @@ export class Navigation<O extends object, R extends object = {}, C extends Recor
|
|
|
265
286
|
* @param options Options that will be passed to the navigator
|
|
266
287
|
* @param info Information that will be added to the history
|
|
267
288
|
*/
|
|
268
|
-
public to(path: RoutePath, options: O = null as O, info = {}) {
|
|
289
|
+
public to(path: RoutePath, options: O = null as unknown as O, info = {}) {
|
|
269
290
|
if (this.config.historyEnabled) {
|
|
270
291
|
this.putHistory(path, this.merge(options, info))
|
|
271
292
|
}
|
package/src/types.ts
CHANGED
|
@@ -1,3 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Recursively extracts the names of all `{{param}}` placeholders from a route
|
|
3
|
+
* string literal as a union of string literal types.
|
|
4
|
+
*
|
|
5
|
+
* Returns `never` when the string contains no placeholders, making it safe to
|
|
6
|
+
* use as a constraint — a route with no params produces an empty `Record<never, …>`.
|
|
7
|
+
*/
|
|
1
8
|
export type ExtractParams<T extends string> =
|
|
2
9
|
T extends `${infer _Start}{{${infer Param}}}${infer Rest}`
|
|
3
10
|
? Param | ExtractParams<Rest>
|
|
@@ -21,22 +28,49 @@ type ExtractRoutes<T, PM, Prefix extends string = ''> = {
|
|
|
21
28
|
type UnionToIntersection<U> =
|
|
22
29
|
(U extends any ? (x: U) => void : never) extends ((x: infer I) => void) ? I : never
|
|
23
30
|
|
|
31
|
+
/**
|
|
32
|
+
* Flattens a nested route definition object into a single map of dot-separated
|
|
33
|
+
* route keys → union of their `{{param}}` placeholder names.
|
|
34
|
+
*
|
|
35
|
+
* The resulting intersection type is what `Navigation` uses to enforce that
|
|
36
|
+
* every call to `navigate` or `isCurrentRoute` supplies exactly the params
|
|
37
|
+
* declared in the corresponding route string — no more, no fewer.
|
|
38
|
+
*/
|
|
24
39
|
export type Routes<T> = UnionToIntersection<ExtractRoutes<T, Params<T>>>
|
|
25
40
|
|
|
26
41
|
// Navigation types
|
|
27
42
|
|
|
43
|
+
/** An unresolved URL pathname string, before param substitution. */
|
|
28
44
|
export type RoutePath = string
|
|
29
45
|
|
|
46
|
+
/** A map of query-string or URL segment key–value pairs, both typed as `string`. */
|
|
30
47
|
export type RouteParams = {
|
|
31
48
|
[x: string]: string
|
|
32
49
|
}
|
|
33
50
|
|
|
51
|
+
/**
|
|
52
|
+
* The function signature every platform-specific navigator adapter must satisfy.
|
|
53
|
+
*
|
|
54
|
+
* `O` carries platform options (e.g. Next.js router options, `replace` flag).
|
|
55
|
+
* `C` is the shared context object set on `Navigation.context`; pass it through
|
|
56
|
+
* to give the adapter access to auth state, locale, etc. without coupling the
|
|
57
|
+
* types to a specific app.
|
|
58
|
+
*/
|
|
34
59
|
export type Navigator<O extends object = {}, C extends Record<string, any> = {}> = (path: RoutePath, options: O, context?: C) => void
|
|
35
60
|
|
|
61
|
+
/** Escape hatch for untyped key–value bags used internally during deep-merge operations. */
|
|
36
62
|
export type AnyValue = {
|
|
37
63
|
[key: string]: any
|
|
38
64
|
}
|
|
39
65
|
|
|
66
|
+
/**
|
|
67
|
+
* A single entry appended to the internal navigation history.
|
|
68
|
+
*
|
|
69
|
+
* `origin` is `null` in SSR environments where `window` is unavailable.
|
|
70
|
+
* `metadata` is whatever `Config.getMetadata()` returns at the moment of
|
|
71
|
+
* navigation — use this to capture auth state, feature flags, etc.
|
|
72
|
+
* `info` is the merged options + caller-supplied info blob stored for `goBack`.
|
|
73
|
+
*/
|
|
40
74
|
export type HistoryData = {
|
|
41
75
|
origin: string
|
|
42
76
|
date: Date
|
|
@@ -45,9 +79,22 @@ export type HistoryData = {
|
|
|
45
79
|
info: any
|
|
46
80
|
}
|
|
47
81
|
|
|
82
|
+
/**
|
|
83
|
+
* Indexed map of history entries keyed by insertion order (1-based).
|
|
84
|
+
* Only populated when `Config.historyEnabled` is `true`.
|
|
85
|
+
*/
|
|
48
86
|
export type History = Record<number, HistoryData>
|
|
49
87
|
|
|
50
88
|
export type Config = {
|
|
89
|
+
/**
|
|
90
|
+
* When `true`, every call to `Navigation.to` appends an entry to the internal
|
|
91
|
+
* history log and `goBack` uses that log instead of `window.history.back()`.
|
|
92
|
+
* Defaults to `false`.
|
|
93
|
+
*/
|
|
51
94
|
historyEnabled?: boolean
|
|
95
|
+
/**
|
|
96
|
+
* Called at navigation time to capture a snapshot of arbitrary app state
|
|
97
|
+
* (e.g. current user, locale). The return value is stored in `HistoryData.metadata`.
|
|
98
|
+
*/
|
|
52
99
|
getMetadata?: () => any
|
|
53
100
|
}
|
package/package.json.bak
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "@codeleap/web-navigation",
|
|
3
|
-
"version": "6.2.3",
|
|
4
|
-
"main": "src/index.ts",
|
|
5
|
-
"license": "UNLICENSED",
|
|
6
|
-
"repository": {
|
|
7
|
-
"url": "https://github.com/codeleap-uk/internal-libs-monorepo.git",
|
|
8
|
-
"type": "git",
|
|
9
|
-
"directory": "packages/web-navigation"
|
|
10
|
-
},
|
|
11
|
-
"devDependencies": {
|
|
12
|
-
"ts-node-dev": "1.1.8"
|
|
13
|
-
},
|
|
14
|
-
"scripts": {
|
|
15
|
-
"build": "echo 'No build needed'"
|
|
16
|
-
},
|
|
17
|
-
"peerDependencies": {
|
|
18
|
-
"typescript": "5.5.2",
|
|
19
|
-
"@fastify/deepmerge": "3.1.0"
|
|
20
|
-
}
|
|
21
|
-
}
|