@equinor/fusion-framework-module-navigation 6.0.1 → 7.0.0-next.2
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 +83 -5
- package/README.md +694 -0
- package/dist/esm/NavigationConfigurator.interface.js +2 -0
- package/dist/esm/NavigationConfigurator.interface.js.map +1 -0
- package/dist/esm/NavigationConfigurator.js +144 -0
- package/dist/esm/NavigationConfigurator.js.map +1 -0
- package/dist/esm/NavigationProvider.interface.js +2 -0
- package/dist/esm/NavigationProvider.interface.js.map +1 -0
- package/dist/esm/NavigationProvider.js +256 -0
- package/dist/esm/NavigationProvider.js.map +1 -0
- package/dist/esm/enable-navigation.js +52 -0
- package/dist/esm/enable-navigation.js.map +1 -0
- package/dist/esm/events.js +23 -0
- package/dist/esm/events.js.map +1 -0
- package/dist/esm/index.js +6 -5
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/lib/BaseHistory.js +189 -0
- package/dist/esm/lib/BaseHistory.js.map +1 -0
- package/dist/esm/lib/BrowserHistory.js +91 -0
- package/dist/esm/lib/BrowserHistory.js.map +1 -0
- package/dist/esm/lib/BrowserHistoryHashStack.js +53 -0
- package/dist/esm/lib/BrowserHistoryHashStack.js.map +1 -0
- package/dist/esm/lib/BrowserHistoryStack.js +77 -0
- package/dist/esm/lib/BrowserHistoryStack.js.map +1 -0
- package/dist/esm/lib/MemoryHistory.js +47 -0
- package/dist/esm/lib/MemoryHistory.js.map +1 -0
- package/dist/esm/lib/MemoryStack.js +98 -0
- package/dist/esm/lib/MemoryStack.js.map +1 -0
- package/dist/esm/lib/create-history.js +48 -0
- package/dist/esm/lib/create-history.js.map +1 -0
- package/dist/esm/lib/index.js +8 -1
- package/dist/esm/lib/index.js.map +1 -1
- package/dist/esm/lib/state/history.actions.js +71 -0
- package/dist/esm/lib/state/history.actions.js.map +1 -0
- package/dist/esm/lib/state/history.flows.js +212 -0
- package/dist/esm/lib/state/history.flows.js.map +1 -0
- package/dist/esm/lib/state/history.reducer.js +59 -0
- package/dist/esm/lib/state/history.reducer.js.map +1 -0
- package/dist/esm/lib/state/history.state.js +37 -0
- package/dist/esm/lib/state/history.state.js.map +1 -0
- package/dist/esm/lib/state/index.js +4 -0
- package/dist/esm/lib/state/index.js.map +1 -0
- package/dist/esm/lib/types.js +25 -0
- package/dist/esm/lib/types.js.map +1 -0
- package/dist/esm/lib/utils/encode-trailing-whitespace.js +19 -0
- package/dist/esm/lib/utils/encode-trailing-whitespace.js.map +1 -0
- package/dist/esm/lib/utils/has-protocol.js +22 -0
- package/dist/esm/lib/utils/has-protocol.js.map +1 -0
- package/dist/esm/lib/utils/index.js +6 -0
- package/dist/esm/lib/utils/index.js.map +1 -0
- package/dist/esm/lib/utils/path-to-string.js +23 -0
- package/dist/esm/lib/utils/path-to-string.js.map +1 -0
- package/dist/esm/lib/utils/path-to-url.js +47 -0
- package/dist/esm/lib/utils/path-to-url.js.map +1 -0
- package/dist/esm/lib/utils/resolve-browser-location.js +53 -0
- package/dist/esm/lib/utils/resolve-browser-location.js.map +1 -0
- package/dist/esm/lib/utils/resolve-path.js +21 -0
- package/dist/esm/lib/utils/resolve-path.js.map +1 -0
- package/dist/esm/module.js +34 -25
- package/dist/esm/module.js.map +1 -1
- 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 +60 -0
- package/dist/types/NavigationConfigurator.interface.d.ts +17 -0
- package/dist/types/NavigationProvider.d.ts +112 -0
- package/dist/types/NavigationProvider.interface.d.ts +75 -0
- package/dist/types/enable-navigation.d.ts +40 -0
- package/dist/types/events.d.ts +48 -0
- package/dist/types/index.d.ts +13 -6
- package/dist/types/lib/BaseHistory.d.ts +122 -0
- package/dist/types/lib/BrowserHistory.d.ts +53 -0
- package/dist/types/lib/BrowserHistoryHashStack.d.ts +41 -0
- package/dist/types/lib/BrowserHistoryStack.d.ts +51 -0
- package/dist/types/lib/MemoryHistory.d.ts +27 -0
- package/dist/types/lib/MemoryStack.d.ts +57 -0
- package/dist/types/lib/create-history.d.ts +35 -0
- package/dist/types/lib/index.d.ts +7 -1
- package/dist/types/lib/state/history.actions.d.ts +61 -0
- package/dist/types/lib/state/history.flows.d.ts +102 -0
- package/dist/types/lib/state/history.reducer.d.ts +85 -0
- package/dist/types/lib/state/history.state.d.ts +27 -0
- package/dist/types/lib/state/index.d.ts +3 -0
- package/dist/types/lib/types.d.ts +145 -0
- package/dist/types/lib/utils/encode-trailing-whitespace.d.ts +16 -0
- package/dist/types/lib/utils/has-protocol.d.ts +19 -0
- package/dist/types/lib/utils/index.d.ts +5 -0
- package/dist/types/lib/utils/path-to-string.d.ts +17 -0
- package/dist/types/lib/utils/path-to-url.d.ts +32 -0
- package/dist/types/lib/utils/resolve-browser-location.d.ts +42 -0
- package/dist/types/lib/utils/resolve-path.d.ts +17 -0
- package/dist/types/module.d.ts +33 -5
- package/dist/types/version.d.ts +1 -1
- package/package.json +25 -7
- package/src/NavigationConfigurator.interface.ts +18 -0
- package/src/NavigationConfigurator.ts +184 -0
- package/src/NavigationProvider.interface.ts +86 -0
- package/src/NavigationProvider.ts +313 -0
- package/src/__tests__/BrowserHistory.test.ts +151 -0
- package/src/__tests__/HashHistory.test.ts +121 -0
- package/src/__tests__/MemoryHistory.test.ts +185 -0
- package/src/__tests__/NavigationProvider.test.ts +60 -0
- package/src/__tests__/setup.ts +8 -0
- package/src/enable-navigation.ts +59 -0
- package/src/events.ts +65 -0
- package/src/index.ts +27 -6
- package/src/lib/BaseHistory.ts +229 -0
- package/src/lib/BrowserHistory.ts +123 -0
- package/src/lib/BrowserHistoryHashStack.ts +56 -0
- package/src/lib/BrowserHistoryStack.ts +82 -0
- package/src/lib/MemoryHistory.ts +66 -0
- package/src/lib/MemoryStack.ts +106 -0
- package/src/lib/create-history.ts +63 -0
- package/src/lib/index.ts +22 -1
- package/src/lib/state/history.actions.ts +108 -0
- package/src/lib/state/history.flows.ts +279 -0
- package/src/lib/state/history.reducer.ts +70 -0
- package/src/lib/state/history.state.ts +62 -0
- package/src/lib/state/index.ts +3 -0
- package/src/lib/types.ts +159 -0
- package/src/lib/utils/encode-trailing-whitespace.ts +18 -0
- package/src/lib/utils/has-protocol.ts +21 -0
- package/src/lib/utils/index.ts +5 -0
- package/src/lib/utils/path-to-string.ts +24 -0
- package/src/lib/utils/path-to-url.ts +52 -0
- package/src/lib/utils/resolve-browser-location.ts +60 -0
- package/src/lib/utils/resolve-path.ts +22 -0
- package/src/module.ts +53 -37
- package/src/version.ts +1 -1
- package/tsconfig.json +10 -1
- package/vitest.config.ts +14 -0
- package/dist/esm/configurator.js +0 -5
- package/dist/esm/configurator.js.map +0 -1
- package/dist/esm/createHistory.js +0 -18
- package/dist/esm/createHistory.js.map +0 -1
- package/dist/esm/lib/provider/INavigationProvider.js +0 -2
- package/dist/esm/lib/provider/INavigationProvider.js.map +0 -1
- package/dist/esm/lib/provider/NavigationProvider.js +0 -82
- package/dist/esm/lib/provider/NavigationProvider.js.map +0 -1
- package/dist/esm/lib/provider/index.js +0 -2
- package/dist/esm/lib/provider/index.js.map +0 -1
- package/dist/esm/navigator.js +0 -158
- package/dist/esm/navigator.js.map +0 -1
- package/dist/esm/types.js +0 -2
- package/dist/esm/types.js.map +0 -1
- package/dist/types/configurator.d.ts +0 -9
- package/dist/types/createHistory.d.ts +0 -4
- package/dist/types/lib/provider/INavigationProvider.d.ts +0 -38
- package/dist/types/lib/provider/NavigationProvider.d.ts +0 -22
- package/dist/types/lib/provider/index.d.ts +0 -2
- package/dist/types/navigator.d.ts +0 -105
- package/dist/types/types.d.ts +0 -3
- package/src/configurator.ts +0 -11
- package/src/createHistory.ts +0 -21
- package/src/lib/provider/INavigationProvider.ts +0 -46
- package/src/lib/provider/NavigationProvider.ts +0 -117
- package/src/lib/provider/index.ts +0 -2
- package/src/navigator.ts +0 -204
- package/src/types.ts +0 -4
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import type { HistoryStack, Location, LocationState, To } from './types';
|
|
2
|
+
/**
|
|
3
|
+
* Memory-based history stack implementation.
|
|
4
|
+
*
|
|
5
|
+
* Stores navigation state in memory instead of using browser APIs.
|
|
6
|
+
* Unlike BrowserHistoryStack, push/replace only update the current location
|
|
7
|
+
* (history entries are managed by the reducer, not the stack).
|
|
8
|
+
*/
|
|
9
|
+
export declare class MemoryHistoryStack implements HistoryStack {
|
|
10
|
+
#private;
|
|
11
|
+
/**
|
|
12
|
+
* Gets the origin of the history stack.
|
|
13
|
+
* Always returns 'memory://' for in-memory storage.
|
|
14
|
+
*/
|
|
15
|
+
get origin(): string;
|
|
16
|
+
/**
|
|
17
|
+
* Gets the current location.
|
|
18
|
+
*/
|
|
19
|
+
get current(): Location;
|
|
20
|
+
/**
|
|
21
|
+
* Creates a memory history stack instance.
|
|
22
|
+
*
|
|
23
|
+
* @param options - Configuration options
|
|
24
|
+
* @param options.initialLocation - Optional initial location (defaults to '/')
|
|
25
|
+
*/
|
|
26
|
+
constructor(options?: {
|
|
27
|
+
initialLocation?: Location;
|
|
28
|
+
});
|
|
29
|
+
/**
|
|
30
|
+
* Pushes a new entry onto the history stack.
|
|
31
|
+
*
|
|
32
|
+
* Only updates the current location. History entries are managed by the reducer.
|
|
33
|
+
*/
|
|
34
|
+
push(location: Location): void;
|
|
35
|
+
/**
|
|
36
|
+
* Replaces the current entry in the history stack.
|
|
37
|
+
*
|
|
38
|
+
* Only updates the current location. History entries are managed by the reducer.
|
|
39
|
+
*/
|
|
40
|
+
replace(location: Location): void;
|
|
41
|
+
/**
|
|
42
|
+
* Navigates backward or forward in the history stack.
|
|
43
|
+
*
|
|
44
|
+
* Uses the history state to find the target location by index.
|
|
45
|
+
* Clamps to valid range (first or last entry if out of bounds).
|
|
46
|
+
*
|
|
47
|
+
* @param delta - Number of steps to move (negative for back, positive for forward)
|
|
48
|
+
* @param state - Current location state with history entries
|
|
49
|
+
*/
|
|
50
|
+
go(delta: number, state: Readonly<LocationState>): void;
|
|
51
|
+
/**
|
|
52
|
+
* Creates a URL object for a given path.
|
|
53
|
+
*
|
|
54
|
+
* All URLs use the 'memory://' origin since this is in-memory storage.
|
|
55
|
+
*/
|
|
56
|
+
createURL(to: To): URL;
|
|
57
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { MemoryHistory, type MemoryHistoryOptions } from './MemoryHistory';
|
|
2
|
+
import { BrowserHistory, type BrowserHistoryOptions } from './BrowserHistory';
|
|
3
|
+
type HistoryCtorMap = {
|
|
4
|
+
memory: (options?: MemoryHistoryOptions) => MemoryHistory;
|
|
5
|
+
browser: (options?: Omit<BrowserHistoryOptions, 'stack'>) => BrowserHistory;
|
|
6
|
+
hash: (options?: Omit<BrowserHistoryOptions, 'stack'>) => BrowserHistory;
|
|
7
|
+
};
|
|
8
|
+
/**
|
|
9
|
+
* Creates a history instance based on the specified type.
|
|
10
|
+
*
|
|
11
|
+
* Factory function for creating different history implementations:
|
|
12
|
+
* - `'browser'`: Creates a {@link BrowserHistory} instance using regular routing (pathname-based)
|
|
13
|
+
* - `'hash'`: Creates a {@link BrowserHistory} instance using hash routing (hash-based)
|
|
14
|
+
* - `'memory'`: Creates a {@link MemoryHistory} instance for testing or SSR (in-memory)
|
|
15
|
+
*
|
|
16
|
+
* All returned instances are compatible with industry-standard routers (Remix/React Router).
|
|
17
|
+
*
|
|
18
|
+
* @param type - The type of history to create ('browser', 'hash', or 'memory')
|
|
19
|
+
* @param args - Optional arguments for the history type
|
|
20
|
+
* @returns A History instance compatible with industry-standard routers (Remix/React Router)
|
|
21
|
+
*
|
|
22
|
+
* @example
|
|
23
|
+
* ```ts
|
|
24
|
+
* // Regular browser routing
|
|
25
|
+
* const history = createHistory('browser');
|
|
26
|
+
*
|
|
27
|
+
* // Hash-based routing
|
|
28
|
+
* const hashHistory = createHistory('hash');
|
|
29
|
+
*
|
|
30
|
+
* // In-memory history for testing
|
|
31
|
+
* const memoryHistory = createHistory('memory', { initialLocation: { ... } });
|
|
32
|
+
* ```
|
|
33
|
+
*/
|
|
34
|
+
export declare const createHistory: <T extends keyof HistoryCtorMap>(type: T, ...args: Parameters<HistoryCtorMap[T]>) => ReturnType<HistoryCtorMap[T]>;
|
|
35
|
+
export {};
|
|
@@ -1 +1,7 @@
|
|
|
1
|
-
export
|
|
1
|
+
export { BaseHistory } from './BaseHistory';
|
|
2
|
+
export { BrowserHistory } from './BrowserHistory';
|
|
3
|
+
export { MemoryHistory } from './MemoryHistory';
|
|
4
|
+
export { BrowserHistoryStack } from './BrowserHistoryStack';
|
|
5
|
+
export { BrowserHistoryHashStack as HashHistoryStack } from './BrowserHistoryHashStack';
|
|
6
|
+
export { MemoryHistoryStack } from './MemoryStack';
|
|
7
|
+
export type { Action, History, HistoryStack, Location, NavigateOptions, NavigationListener, NavigationUpdate, Path, To, } from './types';
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import type { ActionTypes } from '@equinor/fusion-observable/actions';
|
|
2
|
+
import type { To, NavigateOptions, NavigationBlocker, NavigationUpdate } from '../types';
|
|
3
|
+
/**
|
|
4
|
+
* Navigation actions for history state management.
|
|
5
|
+
*/
|
|
6
|
+
export declare const actions: {
|
|
7
|
+
navigate: import("@equinor/fusion-observable").ActionCreatorWithPreparedPayload<[to: To, options: NavigateOptions], {
|
|
8
|
+
to: To;
|
|
9
|
+
options: NavigateOptions;
|
|
10
|
+
}, "navigation/navigate::request", never, {
|
|
11
|
+
key: string;
|
|
12
|
+
}> & {
|
|
13
|
+
success: import("@equinor/fusion-observable").ActionCreatorWithPreparedPayload<[update: NavigationUpdate], {
|
|
14
|
+
update: NavigationUpdate;
|
|
15
|
+
}, "navigation/navigate::success", never, never>;
|
|
16
|
+
failure: import("@equinor/fusion-observable").ActionCreatorWithPreparedPayload<[error: Error], {
|
|
17
|
+
error: Error;
|
|
18
|
+
}, "navigation/navigate::failure", never, never>;
|
|
19
|
+
};
|
|
20
|
+
abortNavigate: import("@equinor/fusion-observable").ActionCreatorWithPreparedPayload<[reason?: string | undefined], {
|
|
21
|
+
reason: string | undefined;
|
|
22
|
+
}, "navigation/navigate::abort", never, never>;
|
|
23
|
+
go: import("@equinor/fusion-observable").ActionCreatorWithPreparedPayload<[delta: number], {
|
|
24
|
+
delta: number;
|
|
25
|
+
}, "navigation/go::request", never, never> & {
|
|
26
|
+
success: import("@equinor/fusion-observable").ActionCreatorWithPreparedPayload<[update: NavigationUpdate], {
|
|
27
|
+
update: NavigationUpdate;
|
|
28
|
+
}, "navigation/go::success", never, never>;
|
|
29
|
+
failure: import("@equinor/fusion-observable").ActionCreatorWithPreparedPayload<[error: Error], {
|
|
30
|
+
error: Error;
|
|
31
|
+
}, "navigation/go::failure", never, never>;
|
|
32
|
+
};
|
|
33
|
+
pop: import("@equinor/fusion-observable").ActionCreatorWithPreparedPayload<[update?: NavigationUpdate | undefined], {
|
|
34
|
+
update: NavigationUpdate | undefined;
|
|
35
|
+
}, "navigation/pop::request", never, never> & {
|
|
36
|
+
success: import("@equinor/fusion-observable").ActionCreatorWithPreparedPayload<[update: NavigationUpdate], {
|
|
37
|
+
update: NavigationUpdate;
|
|
38
|
+
}, "navigation/pop::success", never, never>;
|
|
39
|
+
failure: import("@equinor/fusion-observable").ActionCreatorWithPreparedPayload<[error: Error], {
|
|
40
|
+
error: Error;
|
|
41
|
+
}, "navigation/pop::failure", never, never>;
|
|
42
|
+
};
|
|
43
|
+
validateLocation: import("@equinor/fusion-observable").ActionCreatorWithPreparedPayload<[], {}, "navigation/navigationValidation::request", never, never> & {
|
|
44
|
+
success: import("@equinor/fusion-observable").ActionCreatorWithPreparedPayload<[update: NavigationUpdate], {
|
|
45
|
+
update: NavigationUpdate;
|
|
46
|
+
}, "navigation/navigationValidation::success", never, never>;
|
|
47
|
+
failure: import("@equinor/fusion-observable").ActionCreatorWithPreparedPayload<[error: Error], {
|
|
48
|
+
error: Error;
|
|
49
|
+
}, "navigation/navigationValidation::failure", never, never>;
|
|
50
|
+
};
|
|
51
|
+
addBlocker: import("@equinor/fusion-observable").ActionCreatorWithPreparedPayload<[blocker: NavigationBlocker], {
|
|
52
|
+
blocker: NavigationBlocker;
|
|
53
|
+
}, "navigation/addBlocker", never, never>;
|
|
54
|
+
removeBlocker: import("@equinor/fusion-observable").ActionCreatorWithPreparedPayload<[blocker: NavigationBlocker], {
|
|
55
|
+
blocker: NavigationBlocker;
|
|
56
|
+
}, "navigation/removeBlocker", never, never>;
|
|
57
|
+
};
|
|
58
|
+
/**
|
|
59
|
+
* Union type of all navigation actions.
|
|
60
|
+
*/
|
|
61
|
+
export type Actions = ActionTypes<typeof actions>;
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import type { Flow } from '@equinor/fusion-observable';
|
|
2
|
+
import { type Actions } from './history.actions';
|
|
3
|
+
import { type LocationState, type HistoryStack } from '../types';
|
|
4
|
+
/**
|
|
5
|
+
* History flow for processing navigation actions.
|
|
6
|
+
*/
|
|
7
|
+
export type HistoryFlow = Flow<Actions, LocationState>;
|
|
8
|
+
/**
|
|
9
|
+
* Factory function that creates a history flow from a stack.
|
|
10
|
+
*/
|
|
11
|
+
export type HistoryFlowCreator = (stack: HistoryStack) => HistoryFlow;
|
|
12
|
+
/**
|
|
13
|
+
* Flow creator for handling navigate actions.
|
|
14
|
+
*
|
|
15
|
+
* Execution flow:
|
|
16
|
+
* 1. Filters for navigate actions
|
|
17
|
+
* 2. Resolves the target path from the action payload
|
|
18
|
+
* 3. Creates a location object with the resolved path, key (from action meta), and optional state
|
|
19
|
+
* 4. Checks if the new location is the same as current to prevent navigation loops
|
|
20
|
+
* 5. Updates the stack based on replace option (replace updates current, otherwise pushes new entry)
|
|
21
|
+
* 6. Returns success action with the new location and appropriate action type (PUSH/REPLACE)
|
|
22
|
+
*/
|
|
23
|
+
export declare const navigate: HistoryFlowCreator;
|
|
24
|
+
/**
|
|
25
|
+
* Flow creator for handling go (back/forward) actions.
|
|
26
|
+
*
|
|
27
|
+
* Execution flow:
|
|
28
|
+
* 1. Filters for go actions
|
|
29
|
+
* 2. Combines with current state to get history entries
|
|
30
|
+
* 3. Moves the stack index by the specified delta (negative for back, positive for forward)
|
|
31
|
+
* 4. Returns success action with POP action type and the new current location
|
|
32
|
+
*/
|
|
33
|
+
export declare const go: HistoryFlowCreator;
|
|
34
|
+
/**
|
|
35
|
+
* Flow creator for handling pop (browser back/forward) actions.
|
|
36
|
+
*
|
|
37
|
+
* Execution flow:
|
|
38
|
+
* 1. Filters for pop actions
|
|
39
|
+
* 2. Uses the location from the action payload or falls back to stack.current
|
|
40
|
+
* 3. Emits a success action with POP action type and the current location
|
|
41
|
+
* 4. Completes the observable immediately (synchronous operation)
|
|
42
|
+
*/
|
|
43
|
+
export declare const pop: HistoryFlowCreator;
|
|
44
|
+
/**
|
|
45
|
+
* Flow creator for checking navigation blockers before processing actions.
|
|
46
|
+
*
|
|
47
|
+
* Execution flow:
|
|
48
|
+
* 1. Filters for navigation actions (navigate, go, pop, validateLocation)
|
|
49
|
+
* 2. Determines the action type (PUSH/REPLACE for navigate, POP for others)
|
|
50
|
+
* 3. Combines with current state to check for active blockers
|
|
51
|
+
* 4. If no blockers exist, passes the action through immediately
|
|
52
|
+
* 5. If blockers exist:
|
|
53
|
+
* - Creates a transition object with action, location, and retry callback
|
|
54
|
+
* - Calls each blocker asynchronously (wrapped in Promise to prevent blocking)
|
|
55
|
+
* - Blockers can call retry() to allow navigation or prevent it by not calling retry()
|
|
56
|
+
* - Waits for all blockers to complete before continuing
|
|
57
|
+
* 6. Returns the original action if navigation is allowed, or completes without emitting if blocked
|
|
58
|
+
*/
|
|
59
|
+
export declare const checkBlockers: HistoryFlowCreator;
|
|
60
|
+
/**
|
|
61
|
+
* Flow creator for validating the current location against history state.
|
|
62
|
+
*
|
|
63
|
+
* Execution flow:
|
|
64
|
+
* 1. Filters for validateLocation actions
|
|
65
|
+
* 2. Combines with current state to access history entries
|
|
66
|
+
* 3. Gets the current location from the stack
|
|
67
|
+
* 4. Searches history for an entry matching the current location's key
|
|
68
|
+
* 5. Validates that:
|
|
69
|
+
* - The location key exists in history (returns failure if not found)
|
|
70
|
+
* - The location state matches the history entry state (returns failure if mismatch)
|
|
71
|
+
* 6. Returns success action with current location if validation passes, failure otherwise
|
|
72
|
+
*/
|
|
73
|
+
export declare const validateCurrentLocation: HistoryFlowCreator;
|
|
74
|
+
/**
|
|
75
|
+
* Creates a combined history flow from multiple flow creators.
|
|
76
|
+
*
|
|
77
|
+
* Execution flow:
|
|
78
|
+
* 1. Creates a preprocessing step that applies blocker checking (unless skipped)
|
|
79
|
+
* 2. Initializes each flow creator with the stack to create individual flows
|
|
80
|
+
* 3. Merges all flows so they process actions in parallel
|
|
81
|
+
* 4. Returns a combined flow that:
|
|
82
|
+
* - First applies preprocessing (blocker checking)
|
|
83
|
+
* - Then processes actions through all merged flows
|
|
84
|
+
* - Emits results from any flow that matches the action
|
|
85
|
+
*
|
|
86
|
+
* @param flowCreators - Array of flow creators to combine
|
|
87
|
+
* @param options - Optional configuration options
|
|
88
|
+
* @param options.skipBlockCheck - If true, skip blocker checking
|
|
89
|
+
* @returns A combined history flow creator
|
|
90
|
+
*/
|
|
91
|
+
export declare const createFlow: (flowCreators: HistoryFlowCreator[], options?: {
|
|
92
|
+
skipBlockCheck?: boolean;
|
|
93
|
+
}) => HistoryFlowCreator;
|
|
94
|
+
/**
|
|
95
|
+
* Collection of flow creators for history state management.
|
|
96
|
+
*/
|
|
97
|
+
export declare const flowCreators: {
|
|
98
|
+
navigate: HistoryFlowCreator;
|
|
99
|
+
go: HistoryFlowCreator;
|
|
100
|
+
pop: HistoryFlowCreator;
|
|
101
|
+
validateCurrentLocation: HistoryFlowCreator;
|
|
102
|
+
};
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import type { LocationState, NavigationUpdate } from '../types';
|
|
2
|
+
/**
|
|
3
|
+
* Creates a reducer for history state management.
|
|
4
|
+
*
|
|
5
|
+
* @param initial - Initial navigation update or function that returns initial state
|
|
6
|
+
* @param options - Optional configuration options
|
|
7
|
+
* @param options.maxHistory - Maximum number of history entries to keep (default: 100)
|
|
8
|
+
* @returns A reducer for history state
|
|
9
|
+
*/
|
|
10
|
+
export declare const createHistoryReducer: (initial: NavigationUpdate | (() => LocationState), options?: {
|
|
11
|
+
maxHistory?: number;
|
|
12
|
+
}) => import("@equinor/fusion-observable").ReducerWithInitialState<LocationState, import("@equinor/fusion-observable").PayloadAction<{
|
|
13
|
+
to: import("..").To;
|
|
14
|
+
options: import("..").NavigateOptions;
|
|
15
|
+
}, "navigation/navigate::request", {
|
|
16
|
+
key: string;
|
|
17
|
+
}, never> | {
|
|
18
|
+
payload: {
|
|
19
|
+
reason: string | undefined;
|
|
20
|
+
};
|
|
21
|
+
type: "navigation/navigate::abort";
|
|
22
|
+
} | {
|
|
23
|
+
payload: {
|
|
24
|
+
delta: number;
|
|
25
|
+
};
|
|
26
|
+
type: "navigation/go::request";
|
|
27
|
+
} | {
|
|
28
|
+
payload: {
|
|
29
|
+
update: NavigationUpdate | undefined;
|
|
30
|
+
};
|
|
31
|
+
type: "navigation/pop::request";
|
|
32
|
+
} | {
|
|
33
|
+
payload: {};
|
|
34
|
+
type: "navigation/navigationValidation::request";
|
|
35
|
+
} | {
|
|
36
|
+
payload: {
|
|
37
|
+
blocker: import("../types").NavigationBlocker;
|
|
38
|
+
};
|
|
39
|
+
type: "navigation/addBlocker";
|
|
40
|
+
} | {
|
|
41
|
+
payload: {
|
|
42
|
+
blocker: import("../types").NavigationBlocker;
|
|
43
|
+
};
|
|
44
|
+
type: "navigation/removeBlocker";
|
|
45
|
+
} | {
|
|
46
|
+
payload: {
|
|
47
|
+
update: NavigationUpdate;
|
|
48
|
+
};
|
|
49
|
+
type: "navigation/navigate::success";
|
|
50
|
+
} | {
|
|
51
|
+
payload: {
|
|
52
|
+
error: Error;
|
|
53
|
+
};
|
|
54
|
+
type: "navigation/navigate::failure";
|
|
55
|
+
} | {
|
|
56
|
+
payload: {
|
|
57
|
+
update: NavigationUpdate;
|
|
58
|
+
};
|
|
59
|
+
type: "navigation/go::success";
|
|
60
|
+
} | {
|
|
61
|
+
payload: {
|
|
62
|
+
error: Error;
|
|
63
|
+
};
|
|
64
|
+
type: "navigation/go::failure";
|
|
65
|
+
} | {
|
|
66
|
+
payload: {
|
|
67
|
+
update: NavigationUpdate;
|
|
68
|
+
};
|
|
69
|
+
type: "navigation/pop::success";
|
|
70
|
+
} | {
|
|
71
|
+
payload: {
|
|
72
|
+
error: Error;
|
|
73
|
+
};
|
|
74
|
+
type: "navigation/pop::failure";
|
|
75
|
+
} | {
|
|
76
|
+
payload: {
|
|
77
|
+
update: NavigationUpdate;
|
|
78
|
+
};
|
|
79
|
+
type: "navigation/navigationValidation::success";
|
|
80
|
+
} | {
|
|
81
|
+
payload: {
|
|
82
|
+
error: Error;
|
|
83
|
+
};
|
|
84
|
+
type: "navigation/navigationValidation::failure";
|
|
85
|
+
}>;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { type FlowState, type ReducerWithInitialState } from '@equinor/fusion-observable';
|
|
2
|
+
import { actions, type Actions } from './history.actions';
|
|
3
|
+
import { type HistoryFlowCreator } from './history.flows';
|
|
4
|
+
import type { HistoryStack, LocationState } from '../types';
|
|
5
|
+
/**
|
|
6
|
+
* History state containing flow state and stack.
|
|
7
|
+
*/
|
|
8
|
+
export type HistoryState = FlowState<LocationState, typeof actions> & {
|
|
9
|
+
stack: HistoryStack;
|
|
10
|
+
};
|
|
11
|
+
/**
|
|
12
|
+
* Default flows for history state management.
|
|
13
|
+
*/
|
|
14
|
+
export declare const defaultFlows: HistoryFlowCreator[];
|
|
15
|
+
/**
|
|
16
|
+
* Creates a history store with the specified stack and reducer.
|
|
17
|
+
*
|
|
18
|
+
* @param stack - The history stack implementation
|
|
19
|
+
* @param reducer - The reducer for history state
|
|
20
|
+
* @param options - Optional configuration options
|
|
21
|
+
* @returns A HistoryState instance
|
|
22
|
+
*/
|
|
23
|
+
export declare const createStore: (stack: HistoryStack, reducer: ReducerWithInitialState<LocationState, Actions>, options?: {
|
|
24
|
+
flows?: HistoryFlowCreator[];
|
|
25
|
+
skipBlockCheck?: boolean;
|
|
26
|
+
validateCurrentLocation?: boolean;
|
|
27
|
+
}) => HistoryState;
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
import type { Observable } from 'rxjs';
|
|
2
|
+
import type { Actions } from './state/history.actions';
|
|
3
|
+
/**
|
|
4
|
+
* Actions represent the type of change to a location value.
|
|
5
|
+
*/
|
|
6
|
+
export declare enum Action {
|
|
7
|
+
/**
|
|
8
|
+
* A POP indicates a change to an arbitrary index in the history stack, such
|
|
9
|
+
* as a back or forward navigation. It does not describe the direction of the
|
|
10
|
+
* navigation, only that the current index changed.
|
|
11
|
+
*
|
|
12
|
+
* Note: This is the default action for newly created history objects.
|
|
13
|
+
*/
|
|
14
|
+
Pop = "POP",
|
|
15
|
+
/**
|
|
16
|
+
* A PUSH indicates a new entry being added to the history stack, such as when
|
|
17
|
+
* a link is clicked and a new page loads.
|
|
18
|
+
*/
|
|
19
|
+
Push = "PUSH",
|
|
20
|
+
/**
|
|
21
|
+
* A REPLACE indicates the entry at the current index in the history stack
|
|
22
|
+
* being replaced by a new one.
|
|
23
|
+
*/
|
|
24
|
+
Replace = "REPLACE"
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Target path for navigation operations.
|
|
28
|
+
* Can be a string path or a Path object.
|
|
29
|
+
*/
|
|
30
|
+
export type To = string | Partial<Path>;
|
|
31
|
+
/**
|
|
32
|
+
* Path object containing pathname, optional search, and optional hash.
|
|
33
|
+
*/
|
|
34
|
+
export type Path = {
|
|
35
|
+
pathname: string;
|
|
36
|
+
search: string;
|
|
37
|
+
hash: string;
|
|
38
|
+
};
|
|
39
|
+
/**
|
|
40
|
+
* Location object representing a navigation entry.
|
|
41
|
+
* Extends Path with state and a unique key.
|
|
42
|
+
*/
|
|
43
|
+
export type Location<T = any> = Path & {
|
|
44
|
+
state: T;
|
|
45
|
+
key: string;
|
|
46
|
+
};
|
|
47
|
+
/**
|
|
48
|
+
* Internal state for history management.
|
|
49
|
+
*/
|
|
50
|
+
export type LocationState = {
|
|
51
|
+
current: NavigationUpdate;
|
|
52
|
+
history: NavigationUpdate[];
|
|
53
|
+
blockers: NavigationBlocker[];
|
|
54
|
+
};
|
|
55
|
+
/**
|
|
56
|
+
* Callback function for listening to navigation changes.
|
|
57
|
+
*/
|
|
58
|
+
export type NavigationListener = (update: Readonly<NavigationUpdate>) => void;
|
|
59
|
+
/**
|
|
60
|
+
* Navigation update event containing action and location.
|
|
61
|
+
*/
|
|
62
|
+
export type NavigationUpdate<A extends string = Action, T = unknown> = {
|
|
63
|
+
delta: number;
|
|
64
|
+
action: Readonly<A>;
|
|
65
|
+
location: Readonly<Location<T>>;
|
|
66
|
+
};
|
|
67
|
+
/**
|
|
68
|
+
* Navigation transition that was blocked.
|
|
69
|
+
* Provides a retry method to allow the navigation to proceed.
|
|
70
|
+
*/
|
|
71
|
+
export interface NavigationTransition extends NavigationUpdate {
|
|
72
|
+
/**
|
|
73
|
+
* Retries the navigation that was blocked.
|
|
74
|
+
*/
|
|
75
|
+
retry(): void;
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Callback function for blocking navigation attempts.
|
|
79
|
+
*/
|
|
80
|
+
export type NavigationBlocker = (transition: NavigationTransition) => void;
|
|
81
|
+
/**
|
|
82
|
+
* Options for controlling navigation behavior.
|
|
83
|
+
*
|
|
84
|
+
* @interface NavigateOptions
|
|
85
|
+
*
|
|
86
|
+
* @property {boolean} [replace] - Determines the navigation action:
|
|
87
|
+
* - `false` (default): Pushes a new entry onto the history stack
|
|
88
|
+
* - `true`: Replaces the current entry in the history stack
|
|
89
|
+
*
|
|
90
|
+
* @property {unknown} [state] - Optional state object to associate with the navigation entry.
|
|
91
|
+
* This state can be accessed later when navigating back to this entry.
|
|
92
|
+
*/
|
|
93
|
+
export interface NavigateOptions {
|
|
94
|
+
replace?: boolean;
|
|
95
|
+
state?: unknown;
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* History interface for managing navigation state.
|
|
99
|
+
* Compatible with industry-standard routers (Remix/React Router) and provides observable state management.
|
|
100
|
+
*/
|
|
101
|
+
export interface History extends Disposable {
|
|
102
|
+
/** Observable stream of navigation state updates. */
|
|
103
|
+
readonly state$: Observable<NavigationUpdate>;
|
|
104
|
+
/** Observable stream of navigation actions. */
|
|
105
|
+
readonly action$: Observable<Actions>;
|
|
106
|
+
/** Current navigation action. */
|
|
107
|
+
readonly action: Action;
|
|
108
|
+
/** Current location in the history stack. */
|
|
109
|
+
readonly location: Location;
|
|
110
|
+
/** Creates a valid href string for a given path. */
|
|
111
|
+
createHref(to: To): string;
|
|
112
|
+
/** Creates a URL object for a given path. */
|
|
113
|
+
createURL(to: To): URL;
|
|
114
|
+
/** Encodes a location by properly URL-encoding the pathname. */
|
|
115
|
+
encodeLocation(to: To): Path;
|
|
116
|
+
/** Pushes a new navigation entry onto the history stack. */
|
|
117
|
+
push(to: To, state?: unknown): void;
|
|
118
|
+
/** Replaces the current history entry with a new one. */
|
|
119
|
+
replace(to: To, state?: unknown): void;
|
|
120
|
+
/** Navigate to a location with explicit options. */
|
|
121
|
+
navigate(to: To, options?: NavigateOptions): void;
|
|
122
|
+
/** Navigates backward or forward in the history stack. */
|
|
123
|
+
go(delta: number): void;
|
|
124
|
+
/** Sets up a listener for navigation changes. */
|
|
125
|
+
listen(listener: NavigationListener): () => void;
|
|
126
|
+
/** Registers a blocker to intercept navigation attempts. */
|
|
127
|
+
block(blocker: NavigationBlocker): VoidFunction;
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* History stack interface for managing navigation entries.
|
|
131
|
+
*/
|
|
132
|
+
export interface HistoryStack {
|
|
133
|
+
/** Origin URL for the history stack. */
|
|
134
|
+
readonly origin: string;
|
|
135
|
+
/** Current location in the stack. */
|
|
136
|
+
readonly current: Location;
|
|
137
|
+
/** Pushes a new entry onto the history stack. */
|
|
138
|
+
push(location: Location): void;
|
|
139
|
+
/** Replaces the current entry in the history stack. */
|
|
140
|
+
replace(location: Location): void;
|
|
141
|
+
/** Navigates backward or forward in the history stack. */
|
|
142
|
+
go(delta: number, state: Readonly<LocationState>): void;
|
|
143
|
+
/** Creates a URL object for a given path. */
|
|
144
|
+
createURL(to: To): URL;
|
|
145
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Encodes trailing whitespace in a string by replacing it with '%20'.
|
|
3
|
+
*
|
|
4
|
+
* @param input - The string to encode
|
|
5
|
+
* @returns The string with trailing whitespace encoded
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```ts
|
|
9
|
+
* encodeTrailingWhitespace('hello ')
|
|
10
|
+
* // 'hello%20'
|
|
11
|
+
*
|
|
12
|
+
* encodeTrailingWhitespace('hello')
|
|
13
|
+
* // 'hello'
|
|
14
|
+
* ```
|
|
15
|
+
*/
|
|
16
|
+
export declare const encodeTrailingWhitespace: (input: string) => string;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Checks if a string has a protocol prefix.
|
|
3
|
+
*
|
|
4
|
+
* @param input - The string to check
|
|
5
|
+
* @returns True if the string starts with a protocol (e.g., 'http:', 'https:', 'file:')
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```ts
|
|
9
|
+
* hasProtocol('https://example.com')
|
|
10
|
+
* // true
|
|
11
|
+
*
|
|
12
|
+
* hasProtocol('/users')
|
|
13
|
+
* // false
|
|
14
|
+
*
|
|
15
|
+
* hasProtocol('file:///path/to/file')
|
|
16
|
+
* // true
|
|
17
|
+
* ```
|
|
18
|
+
*/
|
|
19
|
+
export declare const hasProtocol: (input: string) => boolean;
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export { pathToString } from './path-to-string';
|
|
2
|
+
export { pathToUrl } from './path-to-url';
|
|
3
|
+
export { resolvePath } from './resolve-path';
|
|
4
|
+
export { resolveWindowLocation } from './resolve-browser-location';
|
|
5
|
+
export { resolveHashLocation } from './resolve-browser-location';
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { Path } from '../types';
|
|
2
|
+
/**
|
|
3
|
+
* Converts a Partial<Path> object to a path string.
|
|
4
|
+
*
|
|
5
|
+
* @param to - The path object with optional pathname, search, and hash
|
|
6
|
+
* @returns A path string with properly formatted search and hash
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* ```ts
|
|
10
|
+
* pathToString({ pathname: '/users', search: '?id=1', hash: '#section' })
|
|
11
|
+
* // '/users?id=1#section'
|
|
12
|
+
*
|
|
13
|
+
* pathToString({ pathname: '/users', search: 'id=1', hash: 'section' })
|
|
14
|
+
* // '/users?id=1#section'
|
|
15
|
+
* ```
|
|
16
|
+
*/
|
|
17
|
+
export declare const pathToString: (to: Partial<Path>) => string;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type { To } from '../types';
|
|
2
|
+
/**
|
|
3
|
+
* Converts a path to a URL object.
|
|
4
|
+
*
|
|
5
|
+
* This utility handles various path formats and converts them to standard URL objects.
|
|
6
|
+
* It supports absolute URLs, relative paths, and path objects with pathname/search/hash.
|
|
7
|
+
*
|
|
8
|
+
* @param path - The target path (string, Path object, or Location object)
|
|
9
|
+
* @param origin - Optional origin URL. Defaults to `window.location.origin` in browser environments,
|
|
10
|
+
* or 'http://localhost' in Node.js environments
|
|
11
|
+
* @returns A URL object for the given path
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* ```ts
|
|
15
|
+
* // Absolute URL with custom origin
|
|
16
|
+
* pathToUrl('/users?id=1', 'https://example.com')
|
|
17
|
+
* // URL { href: 'https://example.com/users?id=1', ... }
|
|
18
|
+
*
|
|
19
|
+
* // Complete URL with protocol
|
|
20
|
+
* pathToUrl('https://example.com/users')
|
|
21
|
+
* // URL { href: 'https://example.com/users', ... }
|
|
22
|
+
*
|
|
23
|
+
* // Path object
|
|
24
|
+
* pathToUrl({ pathname: '/users', search: '?id=1' })
|
|
25
|
+
* // URL { href: 'http://localhost/users?id=1', ... }
|
|
26
|
+
*
|
|
27
|
+
* // Browser environment (uses window.location.origin)
|
|
28
|
+
* pathToUrl('/dashboard')
|
|
29
|
+
* // URL { href: 'https://current-site.com/dashboard', ... }
|
|
30
|
+
* ```
|
|
31
|
+
*/
|
|
32
|
+
export declare const pathToUrl: (path: To, origin?: string) => URL;
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import type { Location } from '../types';
|
|
2
|
+
/**
|
|
3
|
+
* Resolves the current location from window.location.
|
|
4
|
+
*
|
|
5
|
+
* @param window - The window object to extract location from
|
|
6
|
+
* @param target - Optional target object with state
|
|
7
|
+
* @returns The current location with pathname, search, hash, state, and key
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* ```ts
|
|
11
|
+
* // If window.location is 'https://example.com/users?id=1#section'
|
|
12
|
+
* resolveWindowLocation(window)
|
|
13
|
+
* // { pathname: '/users', search: '?id=1', hash: '#section', state: undefined, key: 'unknown' }
|
|
14
|
+
*
|
|
15
|
+
* resolveWindowLocation(window, { state: { userId: 123 } })
|
|
16
|
+
* // { pathname: '/users', search: '?id=1', hash: '#section', state: { userId: 123 }, key: 'abc123' }
|
|
17
|
+
* ```
|
|
18
|
+
*/
|
|
19
|
+
export declare const resolveWindowLocation: (window: Window, target?: {
|
|
20
|
+
state: unknown;
|
|
21
|
+
}) => Location;
|
|
22
|
+
/**
|
|
23
|
+
* Resolves the current location from window.location.hash.
|
|
24
|
+
*
|
|
25
|
+
* @param window - The window object to extract location from
|
|
26
|
+
* @param target - Optional target object with state
|
|
27
|
+
* @returns The current location with pathname, search, hash, state, and key
|
|
28
|
+
*
|
|
29
|
+
* @example
|
|
30
|
+
* ```ts
|
|
31
|
+
* // If window.location.hash is '#/users?id=1#section'
|
|
32
|
+
* resolveHashLocation(window)
|
|
33
|
+
* // { pathname: '/users', search: '?id=1', hash: '#section', state: undefined, key: 'unknown' }
|
|
34
|
+
*
|
|
35
|
+
* // If window.location.hash is '#/dashboard'
|
|
36
|
+
* resolveHashLocation(window)
|
|
37
|
+
* // { pathname: '/dashboard', search: '', hash: '', state: undefined, key: 'unknown' }
|
|
38
|
+
* ```
|
|
39
|
+
*/
|
|
40
|
+
export declare const resolveHashLocation: (window: Window, target?: {
|
|
41
|
+
state: unknown;
|
|
42
|
+
}) => Location;
|