@equinor/fusion-framework-module-navigation 7.0.0-next.2 → 7.0.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/CHANGELOG.md +42 -19
- package/README.md +97 -614
- package/dist/esm/NavigationConfigurator.js +29 -6
- package/dist/esm/NavigationConfigurator.js.map +1 -1
- 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/ProxyHistory.js +114 -0
- package/dist/esm/lib/ProxyHistory.js.map +1 -0
- 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 +10 -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.d.ts +10 -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/ProxyHistory.d.ts +68 -0
- package/dist/types/lib/create-history.d.ts +7 -13
- package/dist/types/lib/index.d.ts +10 -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 +12 -13
- package/src/NavigationConfigurator.interface.ts +28 -5
- package/src/NavigationConfigurator.ts +47 -15
- package/src/NavigationProvider.interface.ts +20 -7
- package/src/NavigationProvider.ts +57 -23
- package/src/__tests__/ProxyHistory.test.ts +149 -0
- 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/ProxyHistory.ts +144 -0
- package/src/lib/create-history.ts +7 -13
- package/src/lib/index.ts +11 -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/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
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
import { Subscription } from 'rxjs';
|
|
2
|
+
import type { Observable } from 'rxjs';
|
|
3
|
+
|
|
4
|
+
import type { BaseHistory } from './BaseHistory';
|
|
5
|
+
import type {
|
|
6
|
+
History,
|
|
7
|
+
NavigateOptions,
|
|
8
|
+
NavigationBlocker,
|
|
9
|
+
NavigationListener,
|
|
10
|
+
NavigationUpdate,
|
|
11
|
+
Path,
|
|
12
|
+
To,
|
|
13
|
+
} from './types';
|
|
14
|
+
import type { Actions } from './state/history.actions';
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* A lightweight proxy that delegates every {@link History} operation to an
|
|
18
|
+
* underlying target instance.
|
|
19
|
+
*
|
|
20
|
+
* Use this when you need to pass a conforming `History` object whose backing
|
|
21
|
+
* implementation can be swapped or is not yet available at construction time,
|
|
22
|
+
* or when you want a thin indirection layer without subclassing
|
|
23
|
+
* {@link BaseHistory}.
|
|
24
|
+
*
|
|
25
|
+
* The proxy does **not** own the underlying history; disposing it only tears
|
|
26
|
+
* down subscriptions and blockers registered through the proxy itself.
|
|
27
|
+
*
|
|
28
|
+
* @example
|
|
29
|
+
* ```ts
|
|
30
|
+
* const browser = createHistory('browser');
|
|
31
|
+
* const proxy = new ProxyHistory(browser);
|
|
32
|
+
* proxy.push('/dashboard'); // delegates to browser.push
|
|
33
|
+
* ```
|
|
34
|
+
*/
|
|
35
|
+
export class ProxyHistory implements History {
|
|
36
|
+
/** The underlying history instance all calls are forwarded to. */
|
|
37
|
+
readonly #target: History;
|
|
38
|
+
|
|
39
|
+
/** Teardowns owned by this proxy, cleaned up on dispose. */
|
|
40
|
+
readonly #teardowns = new Subscription();
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* @param target - The history instance to delegate all operations to
|
|
44
|
+
*/
|
|
45
|
+
constructor(target: History) {
|
|
46
|
+
this.#target = target;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/** @inheritdoc */
|
|
50
|
+
get state$(): Observable<NavigationUpdate> {
|
|
51
|
+
return this.#target.state$;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/** @inheritdoc */
|
|
55
|
+
get action$(): Observable<Actions> {
|
|
56
|
+
return this.#target.action$;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/** @inheritdoc */
|
|
60
|
+
get action(): History['action'] {
|
|
61
|
+
return this.#target.action;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/** @inheritdoc */
|
|
65
|
+
get location(): History['location'] {
|
|
66
|
+
return this.#target.location;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/** @inheritdoc */
|
|
70
|
+
createHref(to: To): string {
|
|
71
|
+
return this.#target.createHref(to);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/** @inheritdoc */
|
|
75
|
+
createURL(to: To): URL {
|
|
76
|
+
return this.#target.createURL(to);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/** @inheritdoc */
|
|
80
|
+
encodeLocation(to: To): Path {
|
|
81
|
+
return this.#target.encodeLocation(to);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/** @inheritdoc */
|
|
85
|
+
push(to: To, state?: unknown): void {
|
|
86
|
+
this.#target.push(to, state);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/** @inheritdoc */
|
|
90
|
+
replace(to: To, state?: unknown): void {
|
|
91
|
+
this.#target.replace(to, state);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/** @inheritdoc */
|
|
95
|
+
navigate(to: To, options?: NavigateOptions): void {
|
|
96
|
+
this.#target.navigate(to, options);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/** @inheritdoc */
|
|
100
|
+
go(delta: number): void {
|
|
101
|
+
this.#target.go(delta);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Triggers a POP action on the underlying history to notify framework
|
|
106
|
+
* listeners (e.g. React Router) after programmatic navigation.
|
|
107
|
+
*
|
|
108
|
+
* Delegates to the target's `pop()` when it is a {@link BaseHistory}
|
|
109
|
+
* instance; otherwise this is a no-op.
|
|
110
|
+
*/
|
|
111
|
+
pop(): void {
|
|
112
|
+
if ('pop' in this.#target && typeof this.#target.pop === 'function') {
|
|
113
|
+
(this.#target as BaseHistory).pop();
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/** @inheritdoc */
|
|
118
|
+
listen(listener: NavigationListener): () => void {
|
|
119
|
+
const unlisten = this.#target.listen(listener);
|
|
120
|
+
this.#teardowns.add(unlisten);
|
|
121
|
+
return () => {
|
|
122
|
+
unlisten();
|
|
123
|
+
this.#teardowns.remove(unlisten);
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/** @inheritdoc */
|
|
128
|
+
block(blocker: NavigationBlocker): VoidFunction {
|
|
129
|
+
const unblock = this.#target.block(blocker);
|
|
130
|
+
this.#teardowns.add(unblock);
|
|
131
|
+
return () => {
|
|
132
|
+
unblock();
|
|
133
|
+
this.#teardowns.remove(unblock);
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* Disposes all listeners and blockers registered through this proxy.
|
|
139
|
+
* Does **not** dispose the underlying history.
|
|
140
|
+
*/
|
|
141
|
+
[Symbol.dispose](): void {
|
|
142
|
+
this.#teardowns.unsubscribe();
|
|
143
|
+
}
|
|
144
|
+
}
|
|
@@ -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,7 +1,18 @@
|
|
|
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';
|
|
4
14
|
export { MemoryHistory } from './MemoryHistory';
|
|
15
|
+
export { ProxyHistory } from './ProxyHistory';
|
|
5
16
|
|
|
6
17
|
// History stacks
|
|
7
18
|
export { BrowserHistoryStack } from './BrowserHistoryStack';
|
|
@@ -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,
|
package/src/lib/types.ts
CHANGED
|
@@ -42,12 +42,16 @@ export type Path = {
|
|
|
42
42
|
|
|
43
43
|
/**
|
|
44
44
|
* Location object representing a navigation entry.
|
|
45
|
-
* Extends Path with state and a unique key.
|
|
45
|
+
* Extends {@link Path} with arbitrary state data and a unique key.
|
|
46
|
+
*
|
|
47
|
+
* @template T - The type of the state payload stored in this location entry
|
|
46
48
|
*/
|
|
47
49
|
// biome-ignore lint/suspicious/noExplicitAny: necessary
|
|
48
50
|
export type Location<T = any> = Path & {
|
|
49
51
|
state: T;
|
|
50
52
|
key: string;
|
|
53
|
+
/** Masked path used by react-router 7.13+ for unstable view-transition masking. */
|
|
54
|
+
unstable_mask: Path | undefined;
|
|
51
55
|
};
|
|
52
56
|
|
|
53
57
|
/**
|
|
@@ -65,7 +69,10 @@ export type LocationState = {
|
|
|
65
69
|
export type NavigationListener = (update: Readonly<NavigationUpdate>) => void;
|
|
66
70
|
|
|
67
71
|
/**
|
|
68
|
-
* Navigation update event containing action and
|
|
72
|
+
* Navigation update event containing the action, location, and stack delta.
|
|
73
|
+
*
|
|
74
|
+
* @template A - The type of navigation action (defaults to {@link Action})
|
|
75
|
+
* @template T - The type of the state payload in the location
|
|
69
76
|
*/
|
|
70
77
|
export type NavigationUpdate<A extends string = Action, T = unknown> = {
|
|
71
78
|
delta: number;
|
|
@@ -108,7 +115,16 @@ export interface NavigateOptions {
|
|
|
108
115
|
|
|
109
116
|
/**
|
|
110
117
|
* History interface for managing navigation state.
|
|
111
|
-
*
|
|
118
|
+
*
|
|
119
|
+
* Compatible with Remix / React Router and provides observable
|
|
120
|
+
* state management via RxJS.
|
|
121
|
+
*
|
|
122
|
+
* @example
|
|
123
|
+
* ```ts
|
|
124
|
+
* const history = createHistory('browser');
|
|
125
|
+
* history.push('/dashboard');
|
|
126
|
+
* history.state$.subscribe(update => console.log(update.location.pathname));
|
|
127
|
+
* ```
|
|
112
128
|
*/
|
|
113
129
|
export interface History extends Disposable {
|
|
114
130
|
/** Observable stream of navigation state updates. */
|
|
@@ -120,11 +136,20 @@ export interface History extends Disposable {
|
|
|
120
136
|
/** Current location in the history stack. */
|
|
121
137
|
readonly location: Location;
|
|
122
138
|
|
|
123
|
-
/** Creates a valid href string for a given path.
|
|
139
|
+
/** Creates a valid href string for a given path.
|
|
140
|
+
* @param to - Target path or partial path object
|
|
141
|
+
* @returns Fully-qualified href string
|
|
142
|
+
*/
|
|
124
143
|
createHref(to: To): string;
|
|
125
|
-
/** Creates a URL object for a given path.
|
|
144
|
+
/** Creates a {@link URL} object for a given path.
|
|
145
|
+
* @param to - Target path or partial path object
|
|
146
|
+
* @returns Resolved {@link URL} instance
|
|
147
|
+
*/
|
|
126
148
|
createURL(to: To): URL;
|
|
127
|
-
/** Encodes a location by properly URL-encoding the pathname.
|
|
149
|
+
/** Encodes a location by properly URL-encoding the pathname.
|
|
150
|
+
* @param to - Target path or partial path object
|
|
151
|
+
* @returns A {@link Path} with URL-encoded components
|
|
152
|
+
*/
|
|
128
153
|
encodeLocation(to: To): Path;
|
|
129
154
|
/** Pushes a new navigation entry onto the history stack. */
|
|
130
155
|
push(to: To, state?: unknown): void;
|
|
@@ -134,9 +159,15 @@ export interface History extends Disposable {
|
|
|
134
159
|
navigate(to: To, options?: NavigateOptions): void;
|
|
135
160
|
/** Navigates backward or forward in the history stack. */
|
|
136
161
|
go(delta: number): void;
|
|
137
|
-
/** Sets up a listener for navigation changes.
|
|
162
|
+
/** Sets up a listener for navigation changes.
|
|
163
|
+
* @param listener - Callback invoked on POP actions (browser back/forward)
|
|
164
|
+
* @returns A function that unsubscribes the listener when called
|
|
165
|
+
*/
|
|
138
166
|
listen(listener: NavigationListener): () => void;
|
|
139
|
-
/** Registers a blocker to intercept navigation attempts.
|
|
167
|
+
/** Registers a blocker to intercept navigation attempts.
|
|
168
|
+
* @param blocker - Callback invoked before each navigation to allow or prevent it
|
|
169
|
+
* @returns A function that removes the blocker when called
|
|
170
|
+
*/
|
|
140
171
|
block(blocker: NavigationBlocker): VoidFunction;
|
|
141
172
|
}
|
|
142
173
|
|
|
@@ -31,7 +31,7 @@ const resolveState = (target?: { state: unknown }): { state: unknown; key: strin
|
|
|
31
31
|
export const resolveWindowLocation = (window: Window, target?: { state: unknown }): Location => {
|
|
32
32
|
const { pathname, search, hash } = resolvePath(window.location);
|
|
33
33
|
const { state, key } = resolveState(target);
|
|
34
|
-
return { pathname, search, hash, state, key };
|
|
34
|
+
return { pathname, search, hash, state, key, unstable_mask: undefined };
|
|
35
35
|
};
|
|
36
36
|
|
|
37
37
|
/**
|
|
@@ -56,5 +56,5 @@ export const resolveHashLocation = (window: Window, target?: { state: unknown })
|
|
|
56
56
|
const location = resolveWindowLocation(window, target);
|
|
57
57
|
const { pathname, search, hash } = resolvePath(location.hash?.replace('#', '') ?? '');
|
|
58
58
|
const { state, key } = resolveState(target);
|
|
59
|
-
return { pathname, search, hash, state, key };
|
|
59
|
+
return { pathname, search, hash, state, key, unstable_mask: undefined };
|
|
60
60
|
};
|
package/src/module.ts
CHANGED
|
@@ -46,16 +46,16 @@ export const module: NavigationModule = {
|
|
|
46
46
|
version: new SemanticVersion(version),
|
|
47
47
|
name: moduleKey,
|
|
48
48
|
/**
|
|
49
|
-
*
|
|
49
|
+
* Creates a new {@link NavigationConfigurator} for the module.
|
|
50
50
|
*
|
|
51
|
-
* @returns A
|
|
51
|
+
* @returns A fresh {@link NavigationConfigurator} instance with default settings
|
|
52
52
|
*/
|
|
53
53
|
configure: () => new NavigationConfigurator(),
|
|
54
54
|
/**
|
|
55
55
|
* Initializes the navigation module with validated configuration.
|
|
56
56
|
*
|
|
57
|
-
* @param init - Module initialization arguments
|
|
58
|
-
* @returns A
|
|
57
|
+
* @param init - Module initialization arguments containing config and refs
|
|
58
|
+
* @returns A promise that resolves to a configured {@link NavigationProvider}
|
|
59
59
|
*/
|
|
60
60
|
initialize: async (init) => {
|
|
61
61
|
const config = await init.config.createConfigAsync(init);
|
package/src/version.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
// Generated by genversion.
|
|
2
|
-
export const version = '7.0.
|
|
2
|
+
export const version = '7.0.1';
|