@equinor/fusion-framework-module-navigation 7.0.0-next.2 → 7.0.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/CHANGELOG.md +32 -24
- package/README.md +97 -614
- package/dist/esm/NavigationProvider.js +57 -23
- package/dist/esm/NavigationProvider.js.map +1 -1
- package/dist/esm/events.js +20 -3
- package/dist/esm/events.js.map +1 -1
- package/dist/esm/index.js +23 -0
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/lib/BaseHistory.js +23 -6
- package/dist/esm/lib/BaseHistory.js.map +1 -1
- package/dist/esm/lib/BrowserHistoryStack.js +5 -6
- package/dist/esm/lib/BrowserHistoryStack.js.map +1 -1
- package/dist/esm/lib/MemoryHistory.js +13 -6
- package/dist/esm/lib/MemoryHistory.js.map +1 -1
- package/dist/esm/lib/MemoryStack.js +1 -0
- package/dist/esm/lib/MemoryStack.js.map +1 -1
- package/dist/esm/lib/create-history.js +7 -13
- package/dist/esm/lib/create-history.js.map +1 -1
- package/dist/esm/lib/index.js +9 -0
- package/dist/esm/lib/index.js.map +1 -1
- package/dist/esm/lib/state/history.flows.js +7 -12
- package/dist/esm/lib/state/history.flows.js.map +1 -1
- package/dist/esm/lib/state/history.reducer.js +8 -4
- package/dist/esm/lib/state/history.reducer.js.map +1 -1
- package/dist/esm/lib/state/history.state.js +9 -3
- package/dist/esm/lib/state/history.state.js.map +1 -1
- package/dist/esm/lib/utils/resolve-browser-location.js +2 -2
- package/dist/esm/lib/utils/resolve-browser-location.js.map +1 -1
- package/dist/esm/module.js +4 -4
- package/dist/esm/version.js +1 -1
- package/dist/esm/version.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/types/NavigationConfigurator.interface.d.ts +25 -5
- package/dist/types/NavigationProvider.d.ts +57 -23
- package/dist/types/NavigationProvider.interface.d.ts +20 -7
- package/dist/types/events.d.ts +20 -3
- package/dist/types/index.d.ts +24 -1
- package/dist/types/lib/BaseHistory.d.ts +23 -6
- package/dist/types/lib/BrowserHistoryStack.d.ts +5 -6
- package/dist/types/lib/MemoryHistory.d.ts +5 -5
- package/dist/types/lib/create-history.d.ts +7 -13
- package/dist/types/lib/index.d.ts +9 -0
- package/dist/types/lib/state/history.flows.d.ts +6 -11
- package/dist/types/lib/state/history.reducer.d.ts +8 -4
- package/dist/types/lib/state/history.state.d.ts +9 -3
- package/dist/types/lib/types.d.ts +39 -8
- package/dist/types/version.d.ts +1 -1
- package/package.json +11 -12
- package/src/NavigationConfigurator.interface.ts +28 -5
- package/src/NavigationProvider.interface.ts +20 -7
- package/src/NavigationProvider.ts +57 -23
- package/src/events.ts +20 -3
- package/src/index.ts +25 -1
- package/src/lib/BaseHistory.ts +23 -6
- package/src/lib/BrowserHistoryStack.ts +5 -6
- package/src/lib/MemoryHistory.ts +13 -6
- package/src/lib/MemoryStack.ts +1 -0
- package/src/lib/create-history.ts +7 -13
- package/src/lib/index.ts +10 -0
- package/src/lib/state/history.flows.ts +7 -12
- package/src/lib/state/history.reducer.ts +8 -4
- package/src/lib/state/history.state.ts +9 -3
- package/src/lib/types.ts +39 -8
- package/src/lib/utils/resolve-browser-location.ts +2 -2
- package/src/module.ts +4 -4
- package/src/version.ts +1 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@equinor/fusion-framework-module-navigation",
|
|
3
|
-
"version": "7.0.0
|
|
3
|
+
"version": "7.0.0",
|
|
4
4
|
"description": "Navigation module for Fusion Framework providing routing and navigation capabilities using React Router 7",
|
|
5
5
|
"sideEffects": false,
|
|
6
6
|
"main": "dist/esm/index.js",
|
|
@@ -33,24 +33,23 @@
|
|
|
33
33
|
"dependencies": {
|
|
34
34
|
"@remix-run/router": "^1.23.0",
|
|
35
35
|
"uuid": "^13.0.0",
|
|
36
|
-
"zod": "^4.
|
|
36
|
+
"zod": "^4.3.6"
|
|
37
37
|
},
|
|
38
38
|
"devDependencies": {
|
|
39
|
-
"@types/uuid": "^11.0.0",
|
|
40
39
|
"jsdom": "^27.1.0",
|
|
41
40
|
"rxjs": "^7.8.1",
|
|
42
|
-
"typescript": "^5.
|
|
43
|
-
"vitest": "^
|
|
44
|
-
"@equinor/fusion-framework-module": "^
|
|
45
|
-
"@equinor/fusion-framework-module-event": "^
|
|
46
|
-
"@equinor/fusion-framework-module-telemetry": "^
|
|
47
|
-
"@equinor/fusion-observable": "^
|
|
41
|
+
"typescript": "^5.9.3",
|
|
42
|
+
"vitest": "^4.1.0",
|
|
43
|
+
"@equinor/fusion-framework-module": "^6.0.0",
|
|
44
|
+
"@equinor/fusion-framework-module-event": "^6.0.0",
|
|
45
|
+
"@equinor/fusion-framework-module-telemetry": "^5.0.0",
|
|
46
|
+
"@equinor/fusion-observable": "^9.0.0"
|
|
48
47
|
},
|
|
49
48
|
"peerDependencies": {
|
|
50
|
-
"@remix-run/router": "^1.
|
|
49
|
+
"@remix-run/router": "^1.0.0",
|
|
51
50
|
"rxjs": "^7.0.0",
|
|
52
|
-
"@equinor/fusion-framework-module": "^
|
|
53
|
-
"@equinor/fusion-observable": "^
|
|
51
|
+
"@equinor/fusion-framework-module": "^6.0.0",
|
|
52
|
+
"@equinor/fusion-observable": "^9.0.0"
|
|
54
53
|
},
|
|
55
54
|
"scripts": {
|
|
56
55
|
"build": "tsc -b",
|
|
@@ -4,15 +4,38 @@ import type { IEventModuleProvider } from '@equinor/fusion-framework-module-even
|
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* Configuration object for the navigation module.
|
|
7
|
-
*
|
|
7
|
+
*
|
|
8
|
+
* Provides options for customizing the history implementation, basename prefix,
|
|
9
|
+
* telemetry tracking, and event dispatching used by the {@link NavigationProvider}.
|
|
8
10
|
*/
|
|
9
11
|
export interface INavigationConfigurator {
|
|
10
|
-
/**
|
|
12
|
+
/**
|
|
13
|
+
* Base pathname prefix for the application (e.g. `"/apps/my-app"`).
|
|
14
|
+
*
|
|
15
|
+
* When set, the navigation provider automatically prepends this prefix to
|
|
16
|
+
* outgoing paths and strips it from incoming paths, so consumer code
|
|
17
|
+
* operates on clean, basename-free paths.
|
|
18
|
+
*/
|
|
11
19
|
basename?: string;
|
|
12
|
-
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Custom {@link History} instance for navigation.
|
|
23
|
+
*
|
|
24
|
+
* If not provided, defaults to browser history in browser environments
|
|
25
|
+
* or memory history in Node.js environments. Create instances with
|
|
26
|
+
* {@link createHistory}.
|
|
27
|
+
*/
|
|
13
28
|
history?: History;
|
|
14
|
-
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Telemetry provider for tracking navigation events, location changes,
|
|
32
|
+
* and errors for monitoring and debugging.
|
|
33
|
+
*/
|
|
15
34
|
telemetry?: ITelemetryProvider;
|
|
16
|
-
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Event provider for dispatching {@link NavigateEvent} and {@link NavigatedEvent}.
|
|
38
|
+
* Allows other modules to listen for and react to navigation changes.
|
|
39
|
+
*/
|
|
17
40
|
eventProvider?: IEventModuleProvider;
|
|
18
41
|
}
|
|
@@ -9,7 +9,17 @@ import type { IModuleProvider } from '@equinor/fusion-framework-module';
|
|
|
9
9
|
|
|
10
10
|
/**
|
|
11
11
|
* Navigation provider interface.
|
|
12
|
-
*
|
|
12
|
+
*
|
|
13
|
+
* Provides routing and navigation capabilities with automatic basename
|
|
14
|
+
* localization. Consumers work with clean paths (e.g. `/users`) while the
|
|
15
|
+
* underlying history operates on full paths (e.g. `/apps/my-app/users`).
|
|
16
|
+
*
|
|
17
|
+
* @example
|
|
18
|
+
* ```ts
|
|
19
|
+
* const nav: INavigationProvider = framework.modules.navigation;
|
|
20
|
+
* nav.push('/users');
|
|
21
|
+
* console.log(nav.path.pathname); // '/users'
|
|
22
|
+
* ```
|
|
13
23
|
*/
|
|
14
24
|
export interface INavigationProvider extends IModuleProvider {
|
|
15
25
|
/**
|
|
@@ -41,22 +51,25 @@ export interface INavigationProvider extends IModuleProvider {
|
|
|
41
51
|
/**
|
|
42
52
|
* Creates a router instance from route configuration.
|
|
43
53
|
*
|
|
44
|
-
* @
|
|
45
|
-
* @
|
|
54
|
+
* @deprecated Use `@equinor/fusion-framework-react-router` instead.
|
|
55
|
+
* @param routes - Route configuration objects compatible with Remix/React Router
|
|
56
|
+
* @returns A configured and initialized {@link Router} instance with basename applied
|
|
46
57
|
*/
|
|
47
58
|
createRouter(routes: AgnosticRouteObject[]): Router;
|
|
48
59
|
|
|
49
60
|
/**
|
|
50
|
-
* Creates a localized href string
|
|
61
|
+
* Creates a localized href string including the basename prefix.
|
|
51
62
|
*
|
|
52
|
-
* @param to -
|
|
63
|
+
* @param to - Path or location to resolve (defaults to current path)
|
|
64
|
+
* @returns Fully-qualified href string with basename included
|
|
53
65
|
*/
|
|
54
66
|
createHref(to?: To): string;
|
|
55
67
|
|
|
56
68
|
/**
|
|
57
|
-
* Creates a full URL object
|
|
69
|
+
* Creates a full {@link URL} object including the basename prefix.
|
|
58
70
|
*
|
|
59
|
-
* @param to -
|
|
71
|
+
* @param to - Path or location to resolve (defaults to current path)
|
|
72
|
+
* @returns A {@link URL} instance representing the resolved navigation target
|
|
60
73
|
*/
|
|
61
74
|
createURL(to?: To): URL;
|
|
62
75
|
|
|
@@ -37,17 +37,23 @@ const normalizePathname = (path: string) => path.replace(/\/+/g, '/').replace(/\
|
|
|
37
37
|
|
|
38
38
|
/**
|
|
39
39
|
* Navigation provider implementation.
|
|
40
|
-
*
|
|
40
|
+
*
|
|
41
|
+
* Manages routing and navigation state with automatic basename localization.
|
|
42
|
+
* Wraps a {@link History} instance to expose observable state, path localization,
|
|
43
|
+
* and router creation.
|
|
41
44
|
*
|
|
42
45
|
* @remarks
|
|
43
|
-
*
|
|
44
|
-
* -
|
|
45
|
-
* -
|
|
46
|
-
* -
|
|
47
|
-
* - Handles navigation actions (push, replace, createHref, etc.)
|
|
46
|
+
* - Emits localized paths (basename removed) to consumers via {@link NavigationProvider.state$ | state$}
|
|
47
|
+
* - Internally prefixes paths with the basename before forwarding to the history stack
|
|
48
|
+
* - Creates routers compatible with Remix / React Router via {@link NavigationProvider.createRouter | createRouter}
|
|
49
|
+
* - Dispatches {@link NavigatedEvent} and telemetry on navigation changes
|
|
48
50
|
*
|
|
49
|
-
*
|
|
50
|
-
*
|
|
51
|
+
* @example
|
|
52
|
+
* ```ts
|
|
53
|
+
* const provider = new NavigationProvider({ version, config });
|
|
54
|
+
* provider.push('/users');
|
|
55
|
+
* console.log(provider.path.pathname); // '/users'
|
|
56
|
+
* ```
|
|
51
57
|
*/
|
|
52
58
|
export class NavigationProvider
|
|
53
59
|
extends BaseModuleProvider<INavigationConfigurator>
|
|
@@ -62,14 +68,19 @@ export class NavigationProvider
|
|
|
62
68
|
|
|
63
69
|
/**
|
|
64
70
|
* Observable stream of navigation state updates.
|
|
65
|
-
*
|
|
71
|
+
*
|
|
72
|
+
* Emits localized paths (with basename removed) and filters to only
|
|
73
|
+
* paths within the basename scope. Late subscribers receive the last
|
|
74
|
+
* emitted value immediately.
|
|
66
75
|
*/
|
|
67
76
|
public get state$(): Observable<NavigationUpdate> {
|
|
68
77
|
return this.#state$;
|
|
69
78
|
}
|
|
70
79
|
|
|
71
80
|
/**
|
|
72
|
-
* Gets the basename.
|
|
81
|
+
* Gets the basename prefix configured for this provider.
|
|
82
|
+
*
|
|
83
|
+
* @returns The basename string, or an empty string if none is configured
|
|
73
84
|
*/
|
|
74
85
|
public get basename(): string {
|
|
75
86
|
return this.#basename ?? '';
|
|
@@ -89,22 +100,28 @@ export class NavigationProvider
|
|
|
89
100
|
}
|
|
90
101
|
|
|
91
102
|
/**
|
|
92
|
-
* Gets the history instance.
|
|
103
|
+
* Gets the underlying history instance.
|
|
104
|
+
*
|
|
105
|
+
* @returns The {@link History} instance used for navigation
|
|
93
106
|
*/
|
|
94
107
|
public get history(): History {
|
|
95
108
|
return this.#history;
|
|
96
109
|
}
|
|
97
110
|
|
|
98
111
|
/**
|
|
99
|
-
* Gets the current localized path
|
|
112
|
+
* Gets the current localized path with the basename prefix removed.
|
|
113
|
+
*
|
|
114
|
+
* @returns A {@link Path} object representing the current location without basename
|
|
100
115
|
*/
|
|
101
116
|
public get path(): Path {
|
|
102
117
|
return this._localizePath(this.#history.location);
|
|
103
118
|
}
|
|
104
119
|
|
|
105
120
|
/**
|
|
121
|
+
* Creates a new {@link NavigationProvider}.
|
|
122
|
+
*
|
|
106
123
|
* @param args - Configuration arguments containing module config
|
|
107
|
-
* @throws {Error} If no history is provided in the configuration
|
|
124
|
+
* @throws {Error} If no history instance is provided in the configuration
|
|
108
125
|
*/
|
|
109
126
|
constructor(args: BaseModuleProviderCtorArgs<INavigationConfigurator>) {
|
|
110
127
|
super(args);
|
|
@@ -201,10 +218,10 @@ export class NavigationProvider
|
|
|
201
218
|
/**
|
|
202
219
|
* Creates a router instance from route configuration.
|
|
203
220
|
*
|
|
204
|
-
* @deprecated Use `@equinor/fusion-framework-react-router` instead
|
|
221
|
+
* @deprecated Use `@equinor/fusion-framework-react-router` instead.
|
|
205
222
|
*
|
|
206
|
-
* @param routes - Route configuration objects compatible with
|
|
207
|
-
* @returns A configured and initialized
|
|
223
|
+
* @param routes - Route configuration objects compatible with Remix/React Router
|
|
224
|
+
* @returns A configured and initialized {@link Router} instance with basename applied
|
|
208
225
|
*/
|
|
209
226
|
public createRouter(routes: AgnosticRouteObject[]) {
|
|
210
227
|
this.#telemetry?.trackEvent({
|
|
@@ -225,18 +242,26 @@ export class NavigationProvider
|
|
|
225
242
|
}
|
|
226
243
|
|
|
227
244
|
/**
|
|
228
|
-
* Creates a localized href string
|
|
245
|
+
* Creates a localized href string including the basename prefix.
|
|
229
246
|
*
|
|
230
|
-
* @param to -
|
|
247
|
+
* @param to - Path or location to resolve (defaults to current path)
|
|
248
|
+
* @returns Fully-qualified href string with basename included
|
|
249
|
+
*
|
|
250
|
+
* @example
|
|
251
|
+
* ```ts
|
|
252
|
+
* // basename = '/apps/my-app'
|
|
253
|
+
* provider.createHref('/users'); // '/apps/my-app/users'
|
|
254
|
+
* ```
|
|
231
255
|
*/
|
|
232
256
|
public createHref(to?: To): string {
|
|
233
257
|
return this.#history.createHref(this._createToPath(to ?? this.path));
|
|
234
258
|
}
|
|
235
259
|
|
|
236
260
|
/**
|
|
237
|
-
* Creates a full URL object
|
|
261
|
+
* Creates a full {@link URL} object including the basename prefix.
|
|
238
262
|
*
|
|
239
|
-
* @param to -
|
|
263
|
+
* @param to - Path or location to resolve (defaults to current path)
|
|
264
|
+
* @returns A {@link URL} instance representing the resolved navigation target
|
|
240
265
|
*/
|
|
241
266
|
public createURL(to?: To): URL {
|
|
242
267
|
return this.#history.createURL(this._createToPath(to ?? this.path));
|
|
@@ -277,14 +302,20 @@ export class NavigationProvider
|
|
|
277
302
|
(this.#history as BaseHistory).pop();
|
|
278
303
|
}
|
|
279
304
|
/**
|
|
280
|
-
* Checks
|
|
305
|
+
* Checks whether a pathname falls within the configured basename scope.
|
|
306
|
+
*
|
|
307
|
+
* @param pathname - The pathname to check
|
|
308
|
+
* @returns `true` if the pathname starts with the basename (or no basename is set)
|
|
281
309
|
*/
|
|
282
310
|
protected _isWithinBasenameScope(pathname: string): boolean {
|
|
283
311
|
return this.#basename ? pathname.startsWith(this.#basename) : true;
|
|
284
312
|
}
|
|
285
313
|
|
|
286
314
|
/**
|
|
287
|
-
* Localizes a path by
|
|
315
|
+
* Localizes a path by stripping the basename prefix from the pathname.
|
|
316
|
+
*
|
|
317
|
+
* @param location - The full path to localize
|
|
318
|
+
* @returns A new {@link Path} with the basename removed from the pathname
|
|
288
319
|
*/
|
|
289
320
|
protected _localizePath(location: Path): Path {
|
|
290
321
|
const { pathname, search, hash } = location;
|
|
@@ -296,7 +327,10 @@ export class NavigationProvider
|
|
|
296
327
|
}
|
|
297
328
|
|
|
298
329
|
/**
|
|
299
|
-
* Creates a full path object from a target location,
|
|
330
|
+
* Creates a full path object from a target location, prepending the basename prefix.
|
|
331
|
+
*
|
|
332
|
+
* @param to - The target location (string path or partial {@link Path} object)
|
|
333
|
+
* @returns A partial {@link Path} with basename prepended to the pathname
|
|
300
334
|
*/
|
|
301
335
|
protected _createToPath(to: To): Partial<Path> {
|
|
302
336
|
// Parse the 'to' parameter into path components
|
package/src/events.ts
CHANGED
|
@@ -15,7 +15,16 @@ export interface NavigateEventDetail {
|
|
|
15
15
|
|
|
16
16
|
/**
|
|
17
17
|
* Event emitted before navigation occurs.
|
|
18
|
-
* Can be canceled by calling `preventDefault()
|
|
18
|
+
* Can be canceled by calling `preventDefault()` to block the navigation.
|
|
19
|
+
*
|
|
20
|
+
* @example
|
|
21
|
+
* ```ts
|
|
22
|
+
* eventProvider.addEventListener('onNavigate', (event) => {
|
|
23
|
+
* if (hasUnsavedChanges) {
|
|
24
|
+
* event.preventDefault();
|
|
25
|
+
* }
|
|
26
|
+
* });
|
|
27
|
+
* ```
|
|
19
28
|
*/
|
|
20
29
|
export class NavigateEvent extends FrameworkEvent<
|
|
21
30
|
FrameworkEventInit<NavigateEventDetail, INavigationProvider>
|
|
@@ -41,8 +50,16 @@ export interface NavigatedEventDetail {
|
|
|
41
50
|
}
|
|
42
51
|
|
|
43
52
|
/**
|
|
44
|
-
* Event emitted after navigation
|
|
45
|
-
* Contains the navigation action and
|
|
53
|
+
* Event emitted after navigation completes.
|
|
54
|
+
* Contains the navigation action type and both current and previous locations.
|
|
55
|
+
*
|
|
56
|
+
* @example
|
|
57
|
+
* ```ts
|
|
58
|
+
* eventProvider.addEventListener('onNavigated', (event) => {
|
|
59
|
+
* const { action, current, previous } = event.detail;
|
|
60
|
+
* console.log(`${action}: ${previous.location.pathname} → ${current.location.pathname}`);
|
|
61
|
+
* });
|
|
62
|
+
* ```
|
|
46
63
|
*/
|
|
47
64
|
export class NavigatedEvent extends FrameworkEvent<
|
|
48
65
|
FrameworkEventInit<NavigatedEventDetail, INavigationProvider>
|
package/src/index.ts
CHANGED
|
@@ -1,3 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module @equinor/fusion-framework-module-navigation
|
|
3
|
+
*
|
|
4
|
+
* Navigation module for Fusion Framework providing routing and navigation capabilities.
|
|
5
|
+
*
|
|
6
|
+
* Manages observable navigation state with automatic basename localization,
|
|
7
|
+
* so consumers work with clean paths while the underlying history receives
|
|
8
|
+
* full paths including the basename prefix.
|
|
9
|
+
*
|
|
10
|
+
* @remarks
|
|
11
|
+
* Supports browser, hash, and memory history types. Integrates with
|
|
12
|
+
* `@remix-run/router` for router creation and is compatible with
|
|
13
|
+
* industry-standard routers (Remix / React Router).
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* ```ts
|
|
17
|
+
* import { enableNavigation, createHistory } from '@equinor/fusion-framework-module-navigation';
|
|
18
|
+
*
|
|
19
|
+
* enableNavigation(configurator, '/apps/my-app');
|
|
20
|
+
* ```
|
|
21
|
+
*
|
|
22
|
+
* @packageDocumentation
|
|
23
|
+
*/
|
|
24
|
+
|
|
1
25
|
export type { INavigationConfigurator } from './NavigationConfigurator.interface';
|
|
2
26
|
export { NavigationConfigurator } from './NavigationConfigurator';
|
|
3
27
|
|
|
@@ -26,6 +50,6 @@ export type {
|
|
|
26
50
|
} from './lib/types';
|
|
27
51
|
|
|
28
52
|
/**
|
|
29
|
-
* @deprecated
|
|
53
|
+
* @deprecated Use {@link History} instead.
|
|
30
54
|
*/
|
|
31
55
|
export type { History as INavigator } from './lib';
|
package/src/lib/BaseHistory.ts
CHANGED
|
@@ -16,8 +16,10 @@ import type {
|
|
|
16
16
|
|
|
17
17
|
/**
|
|
18
18
|
* Abstract base class for history implementations.
|
|
19
|
-
*
|
|
20
|
-
*
|
|
19
|
+
*
|
|
20
|
+
* Provides common state management, navigation logic, and subscription
|
|
21
|
+
* lifecycle that is shared across different history backends (browser,
|
|
22
|
+
* hash, memory).
|
|
21
23
|
*/
|
|
22
24
|
export abstract class BaseHistory implements History {
|
|
23
25
|
// Subscriptions for cleanup
|
|
@@ -27,14 +29,18 @@ export abstract class BaseHistory implements History {
|
|
|
27
29
|
#state: HistoryState;
|
|
28
30
|
|
|
29
31
|
/**
|
|
30
|
-
* Gets the current location.
|
|
32
|
+
* Gets the current location in the history stack.
|
|
33
|
+
*
|
|
34
|
+
* @returns The current {@link Location} including pathname, search, hash, state, and key
|
|
31
35
|
*/
|
|
32
36
|
public get location(): History['location'] {
|
|
33
37
|
return this.#state.subject.value.current.location;
|
|
34
38
|
}
|
|
35
39
|
|
|
36
40
|
/**
|
|
37
|
-
* Gets the current action.
|
|
41
|
+
* Gets the current navigation action type.
|
|
42
|
+
*
|
|
43
|
+
* @returns The most recent {@link Action} (`Pop`, `Push`, or `Replace`)
|
|
38
44
|
*/
|
|
39
45
|
public get action(): History['action'] {
|
|
40
46
|
return this.#state.subject.value.current.action;
|
|
@@ -56,7 +62,9 @@ export abstract class BaseHistory implements History {
|
|
|
56
62
|
}
|
|
57
63
|
|
|
58
64
|
/**
|
|
59
|
-
* Checks
|
|
65
|
+
* Checks whether there are any active navigation blockers.
|
|
66
|
+
*
|
|
67
|
+
* @returns `true` if one or more blockers are registered
|
|
60
68
|
*/
|
|
61
69
|
public get hasBlockers(): boolean {
|
|
62
70
|
return this.#state.subject.value.blockers.length > 0;
|
|
@@ -68,13 +76,19 @@ export abstract class BaseHistory implements History {
|
|
|
68
76
|
|
|
69
77
|
/**
|
|
70
78
|
* Creates a valid href string for a given path.
|
|
79
|
+
*
|
|
80
|
+
* @param to - Target path or partial path object
|
|
81
|
+
* @returns Fully-qualified href string
|
|
71
82
|
*/
|
|
72
83
|
public createHref(to: To): string {
|
|
73
84
|
return this.createURL(to).href;
|
|
74
85
|
}
|
|
75
86
|
|
|
76
87
|
/**
|
|
77
|
-
* Creates a URL object for a given path.
|
|
88
|
+
* Creates a {@link URL} object for a given path.
|
|
89
|
+
*
|
|
90
|
+
* @param to - Target path or partial path object
|
|
91
|
+
* @returns Resolved {@link URL} instance
|
|
78
92
|
*/
|
|
79
93
|
public createURL(to: To): URL {
|
|
80
94
|
return this.#state.stack.createURL(to);
|
|
@@ -82,6 +96,9 @@ export abstract class BaseHistory implements History {
|
|
|
82
96
|
|
|
83
97
|
/**
|
|
84
98
|
* Encodes a location by properly URL-encoding the pathname.
|
|
99
|
+
*
|
|
100
|
+
* @param to - Target path or partial path object
|
|
101
|
+
* @returns A {@link Path} with URL-encoded components
|
|
85
102
|
*/
|
|
86
103
|
public encodeLocation(to: To): Path {
|
|
87
104
|
return this.#state.stack.createURL(to);
|
|
@@ -2,17 +2,16 @@ import { pathToString, resolvePath, resolveWindowLocation } from './utils';
|
|
|
2
2
|
import type { HistoryStack, Location, To } from './types';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
|
-
* Browser history stack implementation using native
|
|
5
|
+
* Browser history stack implementation using the native History API.
|
|
6
6
|
*
|
|
7
|
-
* Manages navigation state
|
|
8
|
-
*
|
|
9
|
-
*
|
|
7
|
+
* Manages navigation state via `pushState` / `replaceState` and stores
|
|
8
|
+
* location state in `history.state`. This is the default stack for
|
|
9
|
+
* pathname-based (non-hash) routing.
|
|
10
10
|
*
|
|
11
11
|
* @example
|
|
12
12
|
* ```ts
|
|
13
13
|
* const stack = new BrowserHistoryStack(window);
|
|
14
|
-
* stack.push({ pathname: '/users',
|
|
15
|
-
* // Updates URL to /users and adds entry to history
|
|
14
|
+
* stack.push({ pathname: '/users', search: '', hash: '', key: 'abc', state: null });
|
|
16
15
|
* ```
|
|
17
16
|
*/
|
|
18
17
|
export class BrowserHistoryStack implements HistoryStack {
|
package/src/lib/MemoryHistory.ts
CHANGED
|
@@ -10,7 +10,14 @@ import { createHistoryReducer, createStore } from './state';
|
|
|
10
10
|
const defaultInitialLocation: NavigationUpdate = {
|
|
11
11
|
delta: 0,
|
|
12
12
|
action: Action.Pop,
|
|
13
|
-
location: {
|
|
13
|
+
location: {
|
|
14
|
+
pathname: '/',
|
|
15
|
+
search: '',
|
|
16
|
+
hash: '',
|
|
17
|
+
key: 'unknown',
|
|
18
|
+
state: null,
|
|
19
|
+
unstable_mask: undefined,
|
|
20
|
+
},
|
|
14
21
|
};
|
|
15
22
|
|
|
16
23
|
/**
|
|
@@ -26,11 +33,11 @@ export type MemoryHistoryOptions = {
|
|
|
26
33
|
/**
|
|
27
34
|
* Memory history implementation using in-memory storage.
|
|
28
35
|
*
|
|
29
|
-
*
|
|
30
|
-
* - Testing
|
|
31
|
-
* - SSR
|
|
32
|
-
* - Widgets
|
|
33
|
-
* - Node.js
|
|
36
|
+
* Does not touch browser APIs, making it suitable for:
|
|
37
|
+
* - **Testing** — deterministic navigation state without a DOM
|
|
38
|
+
* - **SSR** — server-side rendering where `window` is unavailable
|
|
39
|
+
* - **Widgets** — embedded apps that must not alter the host page URL
|
|
40
|
+
* - **Node.js** — any environment without browser history APIs
|
|
34
41
|
*/
|
|
35
42
|
export class MemoryHistory extends BaseHistory {
|
|
36
43
|
public constructor(options?: MemoryHistoryOptions) {
|
package/src/lib/MemoryStack.ts
CHANGED
|
@@ -13,25 +13,19 @@ type HistoryCtorMap = {
|
|
|
13
13
|
* Creates a history instance based on the specified type.
|
|
14
14
|
*
|
|
15
15
|
* Factory function for creating different history implementations:
|
|
16
|
-
* - `'browser'`: Creates a {@link BrowserHistory}
|
|
17
|
-
* - `'hash'`: Creates a {@link BrowserHistory}
|
|
18
|
-
* - `'memory'`: Creates a {@link MemoryHistory}
|
|
16
|
+
* - `'browser'`: Creates a {@link BrowserHistory} using pathname-based routing
|
|
17
|
+
* - `'hash'`: Creates a {@link BrowserHistory} using hash-based routing (`#/path`)
|
|
18
|
+
* - `'memory'`: Creates a {@link MemoryHistory} for testing, SSR, or widget apps
|
|
19
19
|
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
* @
|
|
23
|
-
* @
|
|
24
|
-
* @returns A History instance compatible with industry-standard routers (Remix/React Router)
|
|
20
|
+
* @param type - The type of history to create (`'browser'`, `'hash'`, or `'memory'`)
|
|
21
|
+
* @param args - Optional arguments forwarded to the history constructor
|
|
22
|
+
* @returns A {@link History} instance of the requested type
|
|
23
|
+
* @throws {Error} If `type` is not one of `'browser'`, `'hash'`, or `'memory'`
|
|
25
24
|
*
|
|
26
25
|
* @example
|
|
27
26
|
* ```ts
|
|
28
|
-
* // Regular browser routing
|
|
29
27
|
* const history = createHistory('browser');
|
|
30
|
-
*
|
|
31
|
-
* // Hash-based routing
|
|
32
28
|
* const hashHistory = createHistory('hash');
|
|
33
|
-
*
|
|
34
|
-
* // In-memory history for testing
|
|
35
29
|
* const memoryHistory = createHistory('memory', { initialLocation: { ... } });
|
|
36
30
|
* ```
|
|
37
31
|
*/
|
package/src/lib/index.ts
CHANGED
|
@@ -1,3 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Internal history implementations, stacks, and types.
|
|
3
|
+
*
|
|
4
|
+
* @remarks
|
|
5
|
+
* This sub-module is re-exported as `@equinor/fusion-framework-module-navigation/lib`
|
|
6
|
+
* and provides the low-level building blocks for navigation state management.
|
|
7
|
+
*
|
|
8
|
+
* @packageDocumentation
|
|
9
|
+
*/
|
|
10
|
+
|
|
1
11
|
// History implementations
|
|
2
12
|
export { BaseHistory } from './BaseHistory';
|
|
3
13
|
export { BrowserHistory } from './BrowserHistory';
|
|
@@ -47,7 +47,7 @@ export const navigate: HistoryFlowCreator =
|
|
|
47
47
|
const path = resolvePath(payload.to);
|
|
48
48
|
const key = meta.key;
|
|
49
49
|
const { replace, state } = payload.options;
|
|
50
|
-
const nextLocation = { ...path, key, state } satisfies Location;
|
|
50
|
+
const nextLocation = { ...path, key, state, unstable_mask: undefined } satisfies Location;
|
|
51
51
|
// prevent death loop navigation
|
|
52
52
|
if (compareLocation(nextLocation, stack.current)) {
|
|
53
53
|
return actions.abortNavigate('Location is the same as the current location');
|
|
@@ -233,19 +233,14 @@ export const validateCurrentLocation: HistoryFlowCreator =
|
|
|
233
233
|
/**
|
|
234
234
|
* Creates a combined history flow from multiple flow creators.
|
|
235
235
|
*
|
|
236
|
-
*
|
|
237
|
-
*
|
|
238
|
-
*
|
|
239
|
-
* 3. Merges all flows so they process actions in parallel
|
|
240
|
-
* 4. Returns a combined flow that:
|
|
241
|
-
* - First applies preprocessing (blocker checking)
|
|
242
|
-
* - Then processes actions through all merged flows
|
|
243
|
-
* - Emits results from any flow that matches the action
|
|
236
|
+
* Merges all provided flows so they process actions in parallel.
|
|
237
|
+
* Optionally prepends a blocker-checking step that gates navigation
|
|
238
|
+
* actions through registered {@link NavigationBlocker | blockers}.
|
|
244
239
|
*
|
|
245
240
|
* @param flowCreators - Array of flow creators to combine
|
|
246
|
-
* @param options - Optional configuration
|
|
247
|
-
* @param options.skipBlockCheck - If true
|
|
248
|
-
* @returns A combined
|
|
241
|
+
* @param options - Optional configuration
|
|
242
|
+
* @param options.skipBlockCheck - If `true`, skip blocker checking
|
|
243
|
+
* @returns A combined {@link HistoryFlowCreator} that merges all provided flows
|
|
249
244
|
*/
|
|
250
245
|
export const createFlow = (
|
|
251
246
|
flowCreators: HistoryFlowCreator[],
|
|
@@ -14,10 +14,14 @@ const findIndex = (state: LocationState) => {
|
|
|
14
14
|
/**
|
|
15
15
|
* Creates a reducer for history state management.
|
|
16
16
|
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
17
|
+
* Handles navigate, go, and pop success actions by updating the
|
|
18
|
+
* history array and current location. Enforces a maximum history
|
|
19
|
+
* length to prevent unbounded memory growth.
|
|
20
|
+
*
|
|
21
|
+
* @param initial - Initial navigation update or factory returning initial state
|
|
22
|
+
* @param options - Optional configuration
|
|
23
|
+
* @param options.maxHistory - Maximum number of history entries to keep (default: `100`)
|
|
24
|
+
* @returns A reducer with initial state for use with {@link createStore}
|
|
21
25
|
*/
|
|
22
26
|
export const createHistoryReducer = (
|
|
23
27
|
initial: NavigationUpdate | (() => LocationState),
|
|
@@ -22,10 +22,16 @@ export const defaultFlows = [flowCreators.navigate, flowCreators.go, flowCreator
|
|
|
22
22
|
/**
|
|
23
23
|
* Creates a history store with the specified stack and reducer.
|
|
24
24
|
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
25
|
+
* Combines the reactive state container with a {@link HistoryStack} and wires
|
|
26
|
+
* up navigation flows for action processing.
|
|
27
|
+
*
|
|
28
|
+
* @param stack - The history stack implementation (browser, hash, or memory)
|
|
29
|
+
* @param reducer - The reducer that handles state transitions
|
|
27
30
|
* @param options - Optional configuration options
|
|
28
|
-
* @
|
|
31
|
+
* @param options.flows - Custom flow creators (defaults to {@link defaultFlows})
|
|
32
|
+
* @param options.skipBlockCheck - Skip blocker checking in flows
|
|
33
|
+
* @param options.validateCurrentLocation - Add location validation flow
|
|
34
|
+
* @returns A fully-initialized {@link HistoryState} with flows attached
|
|
29
35
|
*/
|
|
30
36
|
export const createStore = (
|
|
31
37
|
stack: HistoryStack,
|