@equinor/fusion-framework-module-navigation 7.0.4 → 7.0.5
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 +10 -0
- package/dist/esm/NavigateEvent.js +24 -0
- package/dist/esm/NavigateEvent.js.map +1 -0
- package/dist/esm/NavigatedEvent.js +20 -0
- package/dist/esm/NavigatedEvent.js.map +1 -0
- package/dist/esm/NavigationConfigurator.js +13 -1
- package/dist/esm/NavigationConfigurator.js.map +1 -1
- package/dist/esm/NavigationProvider.js +8 -2
- package/dist/esm/NavigationProvider.js.map +1 -1
- package/dist/esm/enable-navigation.js +1 -0
- package/dist/esm/enable-navigation.js.map +1 -1
- package/dist/esm/index.js +2 -1
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/lib/BaseHistory.js +9 -0
- package/dist/esm/lib/BaseHistory.js.map +1 -1
- package/dist/esm/lib/BrowserHistory.js +1 -0
- package/dist/esm/lib/BrowserHistory.js.map +1 -1
- package/dist/esm/lib/BrowserHistoryHashStack.js +1 -0
- package/dist/esm/lib/BrowserHistoryHashStack.js.map +1 -1
- package/dist/esm/lib/BrowserHistoryStack.js +15 -0
- package/dist/esm/lib/BrowserHistoryStack.js.map +1 -1
- package/dist/esm/lib/MemoryHistory.js +4 -1
- package/dist/esm/lib/MemoryHistory.js.map +1 -1
- package/dist/esm/lib/{MemoryStack.js → MemoryHistoryStack.js} +12 -1
- package/dist/esm/lib/MemoryHistoryStack.js.map +1 -0
- package/dist/esm/lib/ProxyHistory.js +1 -0
- package/dist/esm/lib/ProxyHistory.js.map +1 -1
- package/dist/esm/lib/create-history.js +1 -0
- package/dist/esm/lib/create-history.js.map +1 -1
- package/dist/esm/lib/index.js +1 -1
- package/dist/esm/lib/index.js.map +1 -1
- package/dist/esm/lib/state/{history.actions.js → actions.js} +1 -1
- package/dist/esm/lib/state/actions.js.map +1 -0
- package/dist/esm/lib/state/check-blockers.js +36 -0
- package/dist/esm/lib/state/check-blockers.js.map +1 -0
- package/dist/esm/lib/state/create-flow.js +27 -0
- package/dist/esm/lib/state/create-flow.js.map +1 -0
- package/dist/esm/lib/state/{history.reducer.js → create-history-reducer.js} +5 -2
- package/dist/esm/lib/state/create-history-reducer.js.map +1 -0
- package/dist/esm/lib/state/create-store.js +26 -0
- package/dist/esm/lib/state/create-store.js.map +1 -0
- package/dist/esm/lib/state/flow-creators.js +7 -0
- package/dist/esm/lib/state/flow-creators.js.map +1 -0
- package/dist/esm/lib/state/go.js +12 -0
- package/dist/esm/lib/state/go.js.map +1 -0
- package/dist/esm/lib/state/history.state.js +1 -39
- package/dist/esm/lib/state/history.state.js.map +1 -1
- package/dist/esm/lib/state/index.js +3 -3
- package/dist/esm/lib/state/index.js.map +1 -1
- package/dist/esm/lib/state/navigate.js +43 -0
- package/dist/esm/lib/state/navigate.js.map +1 -0
- package/dist/esm/lib/state/pop.js +14 -0
- package/dist/esm/lib/state/pop.js.map +1 -0
- package/dist/esm/lib/state/validate-current-location.js +26 -0
- package/dist/esm/lib/state/validate-current-location.js.map +1 -0
- package/dist/esm/lib/utils/index.js +2 -2
- package/dist/esm/lib/utils/index.js.map +1 -1
- package/dist/esm/lib/utils/resolve-browser-location.js +1 -52
- package/dist/esm/lib/utils/resolve-browser-location.js.map +1 -1
- package/dist/esm/lib/utils/resolve-hash-location.js +20 -0
- package/dist/esm/lib/utils/resolve-hash-location.js.map +1 -0
- package/dist/esm/lib/utils/resolve-window-location.js +18 -0
- package/dist/esm/lib/utils/resolve-window-location.js.map +1 -0
- package/dist/esm/version.js +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/types/NavigateEvent.d.ts +36 -0
- package/dist/types/NavigatedEvent.d.ts +28 -0
- package/dist/types/NavigationConfigurator.d.ts +3 -0
- package/dist/types/NavigationProvider.d.ts +3 -0
- package/dist/types/index.d.ts +2 -1
- package/dist/types/lib/BaseHistory.d.ts +8 -0
- package/dist/types/lib/BrowserHistoryHashStack.d.ts +1 -0
- package/dist/types/lib/BrowserHistoryStack.d.ts +14 -0
- package/dist/types/lib/MemoryHistory.d.ts +3 -0
- package/dist/types/lib/{MemoryStack.d.ts → MemoryHistoryStack.d.ts} +6 -0
- package/dist/types/lib/ProxyHistory.d.ts +1 -1
- package/dist/types/lib/index.d.ts +1 -1
- package/dist/types/lib/state/check-blockers.d.ts +3 -0
- package/dist/types/lib/state/create-flow.d.ts +10 -0
- package/dist/types/lib/state/{history.reducer.d.ts → create-history-reducer.d.ts} +32 -32
- package/dist/types/lib/state/create-store.d.ts +17 -0
- package/dist/types/lib/state/flow-creators.d.ts +7 -0
- package/dist/types/lib/state/go.d.ts +3 -0
- package/dist/types/lib/state/history.state.d.ts +2 -23
- package/dist/types/lib/state/index.d.ts +4 -3
- package/dist/types/lib/state/navigate.d.ts +9 -0
- package/dist/types/lib/state/pop.d.ts +3 -0
- package/dist/types/lib/state/validate-current-location.d.ts +3 -0
- package/dist/types/lib/types.d.ts +1 -1
- package/dist/types/lib/utils/index.d.ts +2 -2
- package/dist/types/lib/utils/resolve-browser-location.d.ts +1 -42
- package/dist/types/lib/utils/resolve-hash-location.d.ts +10 -0
- package/dist/types/lib/utils/resolve-window-location.d.ts +10 -0
- package/dist/types/version.d.ts +1 -1
- package/package.json +8 -8
- package/src/NavigateEvent.ts +47 -0
- package/src/NavigatedEvent.ts +35 -0
- package/src/NavigationConfigurator.ts +13 -3
- package/src/NavigationProvider.interface.ts +1 -1
- package/src/NavigationProvider.ts +8 -2
- package/src/enable-navigation.ts +1 -0
- package/src/index.ts +2 -6
- package/src/lib/BaseHistory.ts +9 -0
- package/src/lib/BrowserHistory.ts +1 -0
- package/src/lib/BrowserHistoryHashStack.ts +1 -0
- package/src/lib/BrowserHistoryStack.ts +15 -0
- package/src/lib/MemoryHistory.ts +4 -1
- package/src/lib/{MemoryStack.ts → MemoryHistoryStack.ts} +11 -0
- package/src/lib/ProxyHistory.ts +2 -1
- package/src/lib/create-history.ts +1 -0
- package/src/lib/index.ts +1 -1
- package/src/lib/state/check-blockers.ts +52 -0
- package/src/lib/state/create-flow.ts +36 -0
- package/src/lib/state/{history.reducer.ts → create-history-reducer.ts} +4 -1
- package/src/lib/state/create-store.ts +39 -0
- package/src/lib/state/flow-creators.ts +7 -0
- package/src/lib/state/go.ts +20 -0
- package/src/lib/state/history.state.ts +2 -56
- package/src/lib/state/index.ts +4 -3
- package/src/lib/state/navigate.ts +58 -0
- package/src/lib/state/pop.ts +24 -0
- package/src/lib/state/validate-current-location.ts +33 -0
- package/src/lib/types.ts +1 -1
- package/src/lib/utils/index.ts +2 -2
- package/src/lib/utils/resolve-browser-location.ts +1 -60
- package/src/lib/utils/resolve-hash-location.ts +26 -0
- package/src/lib/utils/resolve-window-location.ts +24 -0
- package/src/version.ts +1 -1
- package/dist/esm/events.js +0 -40
- package/dist/esm/events.js.map +0 -1
- package/dist/esm/lib/MemoryStack.js.map +0 -1
- package/dist/esm/lib/state/history.actions.js.map +0 -1
- package/dist/esm/lib/state/history.flows.js +0 -207
- package/dist/esm/lib/state/history.flows.js.map +0 -1
- package/dist/esm/lib/state/history.reducer.js.map +0 -1
- package/dist/types/events.d.ts +0 -65
- package/dist/types/lib/state/history.flows.d.ts +0 -97
- package/src/events.ts +0 -82
- package/src/lib/state/history.flows.ts +0 -274
- /package/dist/types/lib/state/{history.actions.d.ts → actions.d.ts} +0 -0
- /package/src/lib/state/{history.actions.ts → actions.ts} +0 -0
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { go } from './go';
|
|
2
|
+
import { navigate } from './navigate';
|
|
3
|
+
import { pop } from './pop';
|
|
4
|
+
import { validateCurrentLocation } from './validate-current-location';
|
|
5
|
+
|
|
6
|
+
/** Collection of flow creators for history state management. */
|
|
7
|
+
export const flowCreators = { navigate, go, pop, validateCurrentLocation };
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { Observable } from 'rxjs';
|
|
2
|
+
import { map, withLatestFrom } from 'rxjs/operators';
|
|
3
|
+
import type { HistoryFlowCreator } from './navigate';
|
|
4
|
+
import { actions, type Actions } from './actions';
|
|
5
|
+
import { filterAction } from '@equinor/fusion-observable/operators';
|
|
6
|
+
import type { LocationState } from '../types';
|
|
7
|
+
import { Action } from '../types';
|
|
8
|
+
|
|
9
|
+
/** Flow creator for handling go back and forward actions. */
|
|
10
|
+
export const go: HistoryFlowCreator =
|
|
11
|
+
(stack) => (action$: Observable<Actions>, state$: Observable<LocationState>) =>
|
|
12
|
+
// Move the stack by the requested delta and emit the resulting location.
|
|
13
|
+
action$.pipe(
|
|
14
|
+
filterAction(actions.go.type),
|
|
15
|
+
withLatestFrom(state$),
|
|
16
|
+
map(([action, state]) => {
|
|
17
|
+
stack.go(action.payload.delta, state);
|
|
18
|
+
return actions.go.success({ delta: 0, action: Action.Pop, location: stack.current });
|
|
19
|
+
}),
|
|
20
|
+
);
|
|
@@ -1,10 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
type FlowState,
|
|
4
|
-
type ReducerWithInitialState,
|
|
5
|
-
} from '@equinor/fusion-observable';
|
|
6
|
-
import { actions, type Actions } from './history.actions';
|
|
7
|
-
import { flowCreators, createFlow, type HistoryFlowCreator } from './history.flows';
|
|
1
|
+
import type { FlowState } from '@equinor/fusion-observable';
|
|
2
|
+
import type { actions } from './actions';
|
|
8
3
|
import type { HistoryStack, LocationState } from '../types';
|
|
9
4
|
|
|
10
5
|
/**
|
|
@@ -17,52 +12,3 @@ export type HistoryState = FlowState<LocationState, typeof actions> & {
|
|
|
17
12
|
/**
|
|
18
13
|
* Default flows for history state management.
|
|
19
14
|
*/
|
|
20
|
-
export const defaultFlows = [flowCreators.navigate, flowCreators.go, flowCreators.pop];
|
|
21
|
-
|
|
22
|
-
/**
|
|
23
|
-
* Creates a history store with the specified stack and reducer.
|
|
24
|
-
*
|
|
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
|
|
30
|
-
* @param options - Optional configuration options
|
|
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
|
|
35
|
-
*/
|
|
36
|
-
export const createStore = (
|
|
37
|
-
stack: HistoryStack,
|
|
38
|
-
reducer: ReducerWithInitialState<LocationState, Actions>,
|
|
39
|
-
options?: {
|
|
40
|
-
flows?: HistoryFlowCreator[];
|
|
41
|
-
skipBlockCheck?: boolean;
|
|
42
|
-
validateCurrentLocation?: boolean;
|
|
43
|
-
},
|
|
44
|
-
): HistoryState => {
|
|
45
|
-
// Create base state with actions and reducer, then add stack property
|
|
46
|
-
// The stack is stored alongside the flow state for use in flows
|
|
47
|
-
const state = Object.assign(createState(actions, reducer), { stack }) as HistoryState;
|
|
48
|
-
|
|
49
|
-
// Build set of flows to use (default flows or custom flows)
|
|
50
|
-
// Use Set to ensure no duplicates if validateCurrentLocation is added
|
|
51
|
-
const flows = new Set<HistoryFlowCreator>(options?.flows ?? defaultFlows);
|
|
52
|
-
// Optionally add validation flow to check location consistency
|
|
53
|
-
if (options?.validateCurrentLocation) {
|
|
54
|
-
flows.add(flowCreators.validateCurrentLocation);
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
// Create combined flow from all flow creators
|
|
58
|
-
// This merges all flows so they process actions in parallel
|
|
59
|
-
const flow = createFlow([...flows], {
|
|
60
|
-
skipBlockCheck: options?.skipBlockCheck,
|
|
61
|
-
});
|
|
62
|
-
|
|
63
|
-
// Initialize the flow with the stack and add it to the state subject
|
|
64
|
-
// The flow processes actions and updates state through the reducer
|
|
65
|
-
state.subject.addFlow(flow(stack));
|
|
66
|
-
|
|
67
|
-
return state;
|
|
68
|
-
};
|
package/src/lib/state/index.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
-
export { createStore
|
|
2
|
-
export {
|
|
3
|
-
export {
|
|
1
|
+
export { createStore } from './create-store';
|
|
2
|
+
export type { HistoryState } from './history.state';
|
|
3
|
+
export { createHistoryReducer } from './create-history-reducer';
|
|
4
|
+
export { actions, type Actions } from './actions';
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import type { Observable } from 'rxjs';
|
|
2
|
+
import { map } from 'rxjs/operators';
|
|
3
|
+
import type { Flow } from '@equinor/fusion-observable';
|
|
4
|
+
import { filterAction } from '@equinor/fusion-observable/operators';
|
|
5
|
+
import { actions, type Actions } from './actions';
|
|
6
|
+
import { resolvePath } from '../utils';
|
|
7
|
+
import { type Location, type LocationState, type HistoryStack, Action } from '../types';
|
|
8
|
+
|
|
9
|
+
/** History flow for processing navigation actions. */
|
|
10
|
+
export type HistoryFlow = Flow<Actions, LocationState>;
|
|
11
|
+
|
|
12
|
+
/** Factory function that creates a history flow from a stack. */
|
|
13
|
+
export type HistoryFlowCreator = (stack: HistoryStack) => HistoryFlow;
|
|
14
|
+
|
|
15
|
+
const compareLocation = (a: Location, b: Location): boolean => {
|
|
16
|
+
return (
|
|
17
|
+
a.hash === b.hash &&
|
|
18
|
+
a.search === b.search &&
|
|
19
|
+
a.pathname === b.pathname &&
|
|
20
|
+
JSON.stringify(a.state) === JSON.stringify(b.state)
|
|
21
|
+
);
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
/** Flow creator for handling navigate actions. */
|
|
25
|
+
export const navigate: HistoryFlowCreator =
|
|
26
|
+
(stack: HistoryStack): HistoryFlow =>
|
|
27
|
+
(action$: Observable<Actions>) => {
|
|
28
|
+
const { navigate } = actions;
|
|
29
|
+
// Transform matching navigation actions into stack updates and success actions.
|
|
30
|
+
return action$.pipe(
|
|
31
|
+
filterAction(navigate.type),
|
|
32
|
+
map((action) => {
|
|
33
|
+
const { payload, meta } = action;
|
|
34
|
+
const path = resolvePath(payload.to);
|
|
35
|
+
const nextLocation = {
|
|
36
|
+
...path,
|
|
37
|
+
key: meta.key,
|
|
38
|
+
state: payload.options.state,
|
|
39
|
+
unstable_mask: undefined,
|
|
40
|
+
} satisfies Location;
|
|
41
|
+
// Abort duplicate navigations to prevent a feedback loop in history state.
|
|
42
|
+
if (compareLocation(nextLocation, stack.current)) {
|
|
43
|
+
return actions.abortNavigate('Location is the same as the current location');
|
|
44
|
+
}
|
|
45
|
+
// Apply replacement or append semantics selected by the navigation request.
|
|
46
|
+
if (payload.options.replace) {
|
|
47
|
+
stack.replace(nextLocation);
|
|
48
|
+
} else {
|
|
49
|
+
stack.push(nextLocation);
|
|
50
|
+
}
|
|
51
|
+
return navigate.success({
|
|
52
|
+
delta: 0,
|
|
53
|
+
action: payload.options.replace ? Action.Replace : Action.Push,
|
|
54
|
+
location: nextLocation,
|
|
55
|
+
});
|
|
56
|
+
}),
|
|
57
|
+
);
|
|
58
|
+
};
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { Observable } from 'rxjs';
|
|
2
|
+
import { concatMap } from 'rxjs/operators';
|
|
3
|
+
import type { HistoryFlowCreator } from './navigate';
|
|
4
|
+
import { actions, type Actions } from './actions';
|
|
5
|
+
import { filterAction } from '@equinor/fusion-observable/operators';
|
|
6
|
+
import type { HistoryStack } from '../types';
|
|
7
|
+
import { Action } from '../types';
|
|
8
|
+
|
|
9
|
+
/** Flow creator for handling POP actions from browser navigation. */
|
|
10
|
+
export const pop: HistoryFlowCreator = (stack: HistoryStack) => (action$: Observable<Actions>) =>
|
|
11
|
+
// Translate a browser-driven POP into a success action carrying its location.
|
|
12
|
+
action$.pipe(
|
|
13
|
+
filterAction(actions.pop.type),
|
|
14
|
+
concatMap(
|
|
15
|
+
(action) =>
|
|
16
|
+
new Observable<Actions>((subscriber) => {
|
|
17
|
+
const currentLocation = action.payload.update?.location ?? stack.current;
|
|
18
|
+
subscriber.next(
|
|
19
|
+
actions.pop.success({ delta: 0, action: Action.Pop, location: currentLocation }),
|
|
20
|
+
);
|
|
21
|
+
subscriber.complete();
|
|
22
|
+
}),
|
|
23
|
+
),
|
|
24
|
+
);
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { Observable } from 'rxjs';
|
|
2
|
+
import { map, withLatestFrom } from 'rxjs/operators';
|
|
3
|
+
import type { HistoryFlowCreator } from './navigate';
|
|
4
|
+
import { actions, type Actions } from './actions';
|
|
5
|
+
import { filterAction } from '@equinor/fusion-observable/operators';
|
|
6
|
+
import { Action, type LocationState, type HistoryStack } from '../types';
|
|
7
|
+
|
|
8
|
+
/** Flow creator that validates the current stack location against reducer state. */
|
|
9
|
+
export const validateCurrentLocation: HistoryFlowCreator =
|
|
10
|
+
(stack: HistoryStack) => (action$: Observable<Actions>, state$: Observable<LocationState>) =>
|
|
11
|
+
// Confirm the browser stack's current key still matches reducer state.
|
|
12
|
+
action$.pipe(
|
|
13
|
+
filterAction(actions.validateLocation.type),
|
|
14
|
+
withLatestFrom(state$),
|
|
15
|
+
map(([, state]) => {
|
|
16
|
+
const currentLocation = stack.current;
|
|
17
|
+
// Find the reducer entry matching the stack key before comparing location state.
|
|
18
|
+
const record = state.history.find(({ location }) => location?.key === currentLocation?.key);
|
|
19
|
+
// Reject validation when the browser stack key is absent from reducer state.
|
|
20
|
+
if (!record) {
|
|
21
|
+
return actions.validateLocation.failure(new Error('Stack state not found'));
|
|
22
|
+
}
|
|
23
|
+
// Reject validation when the stack and reducer carry different location state.
|
|
24
|
+
if (record.location?.state !== currentLocation?.state) {
|
|
25
|
+
return actions.validateLocation.failure(new Error('Stack state mismatch'));
|
|
26
|
+
}
|
|
27
|
+
return actions.validateLocation.success({
|
|
28
|
+
delta: 0,
|
|
29
|
+
action: Action.Pop,
|
|
30
|
+
location: currentLocation,
|
|
31
|
+
});
|
|
32
|
+
}),
|
|
33
|
+
);
|
package/src/lib/types.ts
CHANGED
package/src/lib/utils/index.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export { pathToString } from './path-to-string';
|
|
2
2
|
export { pathToUrl } from './path-to-url';
|
|
3
3
|
export { resolvePath } from './resolve-path';
|
|
4
|
-
export { resolveWindowLocation } from './resolve-
|
|
5
|
-
export { resolveHashLocation } from './resolve-
|
|
4
|
+
export { resolveWindowLocation } from './resolve-window-location';
|
|
5
|
+
export { resolveHashLocation } from './resolve-hash-location';
|
|
@@ -1,60 +1 @@
|
|
|
1
|
-
|
|
2
|
-
import { resolvePath } from './resolve-path';
|
|
3
|
-
|
|
4
|
-
const resolveState = (target?: { state: unknown }): { state: unknown; key: string } => {
|
|
5
|
-
const { value, key = 'unknown' } =
|
|
6
|
-
(target ?? window.history).state ??
|
|
7
|
-
({} as {
|
|
8
|
-
value: unknown;
|
|
9
|
-
key?: string;
|
|
10
|
-
});
|
|
11
|
-
return { state: value, key };
|
|
12
|
-
};
|
|
13
|
-
|
|
14
|
-
/**
|
|
15
|
-
* Resolves the current location from window.location.
|
|
16
|
-
*
|
|
17
|
-
* @param window - The window object to extract location from
|
|
18
|
-
* @param target - Optional target object with state
|
|
19
|
-
* @returns The current location with pathname, search, hash, state, and key
|
|
20
|
-
*
|
|
21
|
-
* @example
|
|
22
|
-
* ```ts
|
|
23
|
-
* // If window.location is 'https://example.com/users?id=1#section'
|
|
24
|
-
* resolveWindowLocation(window)
|
|
25
|
-
* // { pathname: '/users', search: '?id=1', hash: '#section', state: undefined, key: 'unknown' }
|
|
26
|
-
*
|
|
27
|
-
* resolveWindowLocation(window, { state: { userId: 123 } })
|
|
28
|
-
* // { pathname: '/users', search: '?id=1', hash: '#section', state: { userId: 123 }, key: 'abc123' }
|
|
29
|
-
* ```
|
|
30
|
-
*/
|
|
31
|
-
export const resolveWindowLocation = (window: Window, target?: { state: unknown }): Location => {
|
|
32
|
-
const { pathname, search, hash } = resolvePath(window.location);
|
|
33
|
-
const { state, key } = resolveState(target);
|
|
34
|
-
return { pathname, search, hash, state, key, unstable_mask: undefined };
|
|
35
|
-
};
|
|
36
|
-
|
|
37
|
-
/**
|
|
38
|
-
* Resolves the current location from window.location.hash.
|
|
39
|
-
*
|
|
40
|
-
* @param window - The window object to extract location from
|
|
41
|
-
* @param target - Optional target object with state
|
|
42
|
-
* @returns The current location with pathname, search, hash, state, and key
|
|
43
|
-
*
|
|
44
|
-
* @example
|
|
45
|
-
* ```ts
|
|
46
|
-
* // If window.location.hash is '#/users?id=1#section'
|
|
47
|
-
* resolveHashLocation(window)
|
|
48
|
-
* // { pathname: '/users', search: '?id=1', hash: '#section', state: undefined, key: 'unknown' }
|
|
49
|
-
*
|
|
50
|
-
* // If window.location.hash is '#/dashboard'
|
|
51
|
-
* resolveHashLocation(window)
|
|
52
|
-
* // { pathname: '/dashboard', search: '', hash: '', state: undefined, key: 'unknown' }
|
|
53
|
-
* ```
|
|
54
|
-
*/
|
|
55
|
-
export const resolveHashLocation = (window: Window, target?: { state: unknown }): Location => {
|
|
56
|
-
const location = resolveWindowLocation(window, target);
|
|
57
|
-
const { pathname, search, hash } = resolvePath(location.hash?.replace('#', '') ?? '');
|
|
58
|
-
const { state, key } = resolveState(target);
|
|
59
|
-
return { pathname, search, hash, state, key, unstable_mask: undefined };
|
|
60
|
-
};
|
|
1
|
+
export { resolveWindowLocation } from './resolve-window-location';
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { Location } from '../types';
|
|
2
|
+
import { resolvePath } from './resolve-path';
|
|
3
|
+
import { resolveWindowLocation } from './resolve-window-location';
|
|
4
|
+
|
|
5
|
+
const resolveState = (target?: { state: unknown }): { state: unknown; key: string } => {
|
|
6
|
+
const { value, key = 'unknown' } =
|
|
7
|
+
(target ?? window.history).state ??
|
|
8
|
+
({} as {
|
|
9
|
+
value: unknown;
|
|
10
|
+
key?: string;
|
|
11
|
+
});
|
|
12
|
+
return { state: value, key };
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Resolves the current location from window.location.hash.
|
|
17
|
+
* @param window - The window object to extract location from.
|
|
18
|
+
* @param target - Optional target object with state.
|
|
19
|
+
* @returns The current hash-based navigation location.
|
|
20
|
+
*/
|
|
21
|
+
export const resolveHashLocation = (window: Window, target?: { state: unknown }): Location => {
|
|
22
|
+
const location = resolveWindowLocation(window, target);
|
|
23
|
+
const { pathname, search, hash } = resolvePath(location.hash?.replace('#', '') ?? '');
|
|
24
|
+
const { state, key } = resolveState(target);
|
|
25
|
+
return { pathname, search, hash, state, key, unstable_mask: undefined };
|
|
26
|
+
};
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { Location } from '../types';
|
|
2
|
+
import { resolvePath } from './resolve-path';
|
|
3
|
+
|
|
4
|
+
const resolveState = (target?: { state: unknown }): { state: unknown; key: string } => {
|
|
5
|
+
const { value, key = 'unknown' } =
|
|
6
|
+
(target ?? window.history).state ??
|
|
7
|
+
({} as {
|
|
8
|
+
value: unknown;
|
|
9
|
+
key?: string;
|
|
10
|
+
});
|
|
11
|
+
return { state: value, key };
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Resolves the current location from window.location.
|
|
16
|
+
* @param window - The window object to extract location from.
|
|
17
|
+
* @param target - Optional target object with state.
|
|
18
|
+
* @returns The current browser navigation location.
|
|
19
|
+
*/
|
|
20
|
+
export const resolveWindowLocation = (window: Window, target?: { state: unknown }): Location => {
|
|
21
|
+
const { pathname, search, hash } = resolvePath(window.location);
|
|
22
|
+
const { state, key } = resolveState(target);
|
|
23
|
+
return { pathname, search, hash, state, key, unstable_mask: undefined };
|
|
24
|
+
};
|
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.5';
|
package/dist/esm/events.js
DELETED
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
import { FrameworkEvent } from '@equinor/fusion-framework-module-event';
|
|
2
|
-
/**
|
|
3
|
-
* Event emitted before navigation occurs.
|
|
4
|
-
* Can be canceled by calling `preventDefault()` to block the navigation.
|
|
5
|
-
*
|
|
6
|
-
* @example
|
|
7
|
-
* ```ts
|
|
8
|
-
* eventProvider.addEventListener('onNavigate', (event) => {
|
|
9
|
-
* if (hasUnsavedChanges) {
|
|
10
|
-
* event.preventDefault();
|
|
11
|
-
* }
|
|
12
|
-
* });
|
|
13
|
-
* ```
|
|
14
|
-
*/
|
|
15
|
-
export class NavigateEvent extends FrameworkEvent {
|
|
16
|
-
constructor(detail, source) {
|
|
17
|
-
super('onNavigate', {
|
|
18
|
-
detail,
|
|
19
|
-
source,
|
|
20
|
-
});
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
|
-
/**
|
|
24
|
-
* Event emitted after navigation completes.
|
|
25
|
-
* Contains the navigation action type and both current and previous locations.
|
|
26
|
-
*
|
|
27
|
-
* @example
|
|
28
|
-
* ```ts
|
|
29
|
-
* eventProvider.addEventListener('onNavigated', (event) => {
|
|
30
|
-
* const { action, current, previous } = event.detail;
|
|
31
|
-
* console.log(`${action}: ${previous.location.pathname} → ${current.location.pathname}`);
|
|
32
|
-
* });
|
|
33
|
-
* ```
|
|
34
|
-
*/
|
|
35
|
-
export class NavigatedEvent extends FrameworkEvent {
|
|
36
|
-
constructor(detail, source) {
|
|
37
|
-
super('onNavigated', { detail, source });
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
//# sourceMappingURL=events.js.map
|
package/dist/esm/events.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"events.js","sourceRoot":"","sources":["../../src/events.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAA2B,MAAM,wCAAwC,CAAC;AAejG;;;;;;;;;;;;GAYG;AACH,MAAM,OAAO,aAAc,SAAQ,cAElC;IACC,YAAY,MAA2B,EAAE,MAA2B;QAClE,KAAK,CAAC,YAAY,EAAE;YAClB,MAAM;YACN,MAAM;SACP,CAAC,CAAC;IACL,CAAC;CACF;AAcD;;;;;;;;;;;GAWG;AACH,MAAM,OAAO,cAAe,SAAQ,cAEnC;IACC,YAAY,MAA4B,EAAE,MAA2B;QACnE,KAAK,CAAC,aAAa,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;IAC3C,CAAC;CACF"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"MemoryStack.js","sourceRoot":"","sources":["../../../src/lib/MemoryStack.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAEpD;;;;;;GAMG;AACH,MAAM,OAAO,kBAAkB;IAC7B,QAAQ,CAAW;IAEnB;;;OAGG;IACH,IAAI,MAAM;QACR,OAAO,WAAW,CAAC;IACrB,CAAC;IAED;;OAEG;IACH,IAAI,OAAO;QACT,OAAO,IAAI,CAAC,QAAQ,CAAC;IACvB,CAAC;IAED;;;;;OAKG;IACH,YAAY,OAAwC;QAClD,IAAI,CAAC,QAAQ,GAAG,OAAO,EAAE,eAAe,IAAI;YAC1C,QAAQ,EAAE,GAAG;YACb,MAAM,EAAE,EAAE;YACV,IAAI,EAAE,EAAE;YACR,KAAK,EAAE,IAAI;YACX,GAAG,EAAE,EAAE;YACP,aAAa,EAAE,SAAS;SACzB,CAAC;IACJ,CAAC;IAED;;;;OAIG;IACH,IAAI,CAAC,QAAkB;QACrB,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;IAC3B,CAAC;IAED;;;;OAIG;IACH,OAAO,CAAC,QAAkB;QACxB,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;IAC3B,CAAC;IAED;;;;;;;;OAQG;IACH,EAAE,CAAC,KAAa,EAAE,KAA8B;QAC9C,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,GAAG,KAAK,CAAC;QACnC,MAAM,eAAe,GAAG,OAAO,CAAC,QAAQ,IAAI,IAAI,CAAC,QAAQ,CAAC;QAC1D,0CAA0C;QAC1C,MAAM,YAAY,GAAG,OAAO,CAAC,SAAS,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,QAAQ,CAAC,GAAG,KAAK,eAAe,CAAC,GAAG,CAAC,CAAC;QAE9F,gDAAgD;QAChD,IAAI,YAAY,KAAK,CAAC,CAAC,EAAE,CAAC;YACxB,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBACvB,IAAI,CAAC,QAAQ,GAAG,OAAO,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,QAAQ,CAAC;YACvD,CAAC;YACD,OAAO;QACT,CAAC;QAED,kDAAkD;QAClD,MAAM,QAAQ,GAAG,YAAY,GAAG,KAAK,CAAC;QACtC,IAAI,QAAQ,GAAG,CAAC,EAAE,CAAC;YACjB,IAAI,CAAC,QAAQ,GAAG,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC;QAC5C,CAAC;aAAM,IAAI,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC;YAC5C,IAAI,CAAC,QAAQ,GAAG,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,QAAQ,CAAC;QACnE,CAAC;aAAM,CAAC;YACN,IAAI,CAAC,QAAQ,GAAG,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,QAAQ,CAAC;QACnD,CAAC;IACH,CAAC;IAED;;;;OAIG;IACH,SAAS,CAAC,EAAM;QACd,MAAM,IAAI,GAAG,WAAW,CAAC,EAAE,CAAC,CAAC;QAC7B,OAAO,IAAI,GAAG,CAAC,YAAY,CAAC,IAAI,CAAC,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;IAClD,CAAC;CACF"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"history.actions.js","sourceRoot":"","sources":["../../../../src/lib/state/history.actions.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,iBAAiB,EAAE,MAAM,oCAAoC,CAAC;AAErF,OAAO,EAAE,EAAE,IAAI,UAAU,EAAE,MAAM,MAAM,CAAC;AAGxC;;GAEG;AACH,MAAM,cAAc,GAAG,iBAAiB,CACtC,qBAAqB,EACrB,CAAC,EAAM,EAAE,OAAwB,EAAE,EAAE,CAAC,CAAC;IACrC,OAAO,EAAE,EAAE,EAAE,EAAE,OAAO,EAAE;IACxB,IAAI,EAAE,EAAE,GAAG,EAAE,UAAU,EAAE,EAAE;CAC5B,CAAC,EACF,CAAC,MAAwB,EAAE,EAAE,CAAC,CAAC;IAC7B,OAAO,EAAE,EAAE,MAAM,EAAE;CACpB,CAAC,EACF,CAAC,KAAY,EAAE,EAAE,CAAC,CAAC;IACjB,OAAO,EAAE,EAAE,KAAK,EAAE;CACnB,CAAC,CACH,CAAC;AAEF,MAAM,mBAAmB,GAAG,YAAY,CAAC,4BAA4B,EAAE,CAAC,MAAe,EAAE,EAAE,CAAC,CAAC;IAC3F,OAAO,EAAE,EAAE,MAAM,EAAE;CACpB,CAAC,CAAC,CAAC;AAEJ;;GAEG;AACH,MAAM,aAAa,GAAG,iBAAiB,CACrC,eAAe,EACf,CAAC,KAAa,EAAE,EAAE,CAAC,CAAC;IAClB,OAAO,EAAE,EAAE,KAAK,EAAE;CACnB,CAAC,EACF,CAAC,MAAwB,EAAE,EAAE,CAAC,CAAC;IAC7B,OAAO,EAAE,EAAE,MAAM,EAAE;CACpB,CAAC,EACF,CAAC,KAAY,EAAE,EAAE,CAAC,CAAC;IACjB,OAAO,EAAE,EAAE,KAAK,EAAE;CACnB,CAAC,CACH,CAAC;AAEF;;GAEG;AACH,MAAM,cAAc,GAAG,iBAAiB,CACtC,gBAAgB,EAChB,CAAC,MAAyB,EAAE,EAAE,CAAC,CAAC;IAC9B,OAAO,EAAE,EAAE,MAAM,EAAE;CACpB,CAAC,EACF,CAAC,MAAwB,EAAE,EAAE,CAAC,CAAC;IAC7B,OAAO,EAAE,EAAE,MAAM,EAAE;CACpB,CAAC,EACF,CAAC,KAAY,EAAE,EAAE,CAAC,CAAC;IACjB,OAAO,EAAE,EAAE,KAAK,EAAE;CACnB,CAAC,CACH,CAAC;AAEF;;GAEG;AACH,MAAM,sBAAsB,GAAG,iBAAiB,CAC9C,iCAAiC,EACjC,GAAG,EAAE,CAAC,CAAC;IACL,OAAO,EAAE,EAAE;CACZ,CAAC,EACF,CAAC,MAAwB,EAAE,EAAE,CAAC,CAAC;IAC7B,OAAO,EAAE,EAAE,MAAM,EAAE;CACpB,CAAC,EACF,CAAC,KAAY,EAAE,EAAE,CAAC,CAAC;IACjB,OAAO,EAAE,EAAE,KAAK,EAAE;CACnB,CAAC,CACH,CAAC;AAEF;;GAEG;AACH,MAAM,gBAAgB,GAAG,YAAY,CAAC,uBAAuB,EAAE,CAAC,OAA0B,EAAE,EAAE,CAAC,CAAC;IAC9F,OAAO,EAAE,EAAE,OAAO,EAAE;CACrB,CAAC,CAAC,CAAC;AAEJ;;GAEG;AACH,MAAM,mBAAmB,GAAG,YAAY,CACtC,0BAA0B,EAC1B,CAAC,OAA0B,EAAE,EAAE,CAAC,CAAC;IAC/B,OAAO,EAAE,EAAE,OAAO,EAAE;CACrB,CAAC,CACH,CAAC;AAEF;;GAEG;AACH,MAAM,CAAC,MAAM,OAAO,GAAG;IACrB,QAAQ,EAAE,cAAc;IACxB,aAAa,EAAE,mBAAmB;IAClC,EAAE,EAAE,aAAa;IACjB,GAAG,EAAE,cAAc;IACnB,gBAAgB,EAAE,sBAAsB;IACxC,UAAU,EAAE,gBAAgB;IAC5B,aAAa,EAAE,mBAAmB;CACnC,CAAC"}
|
|
@@ -1,207 +0,0 @@
|
|
|
1
|
-
import { Observable, of, merge } from 'rxjs';
|
|
2
|
-
import { concatMap, map, withLatestFrom } from 'rxjs/operators';
|
|
3
|
-
import { filterAction } from '@equinor/fusion-observable/operators';
|
|
4
|
-
import { actions } from './history.actions';
|
|
5
|
-
import { resolvePath } from '../utils';
|
|
6
|
-
import { Action } from '../types';
|
|
7
|
-
const compareLocation = (a, b) => {
|
|
8
|
-
return (a.hash === b.hash &&
|
|
9
|
-
a.search === b.search &&
|
|
10
|
-
a.pathname === b.pathname &&
|
|
11
|
-
JSON.stringify(a.state) === JSON.stringify(b.state));
|
|
12
|
-
};
|
|
13
|
-
/**
|
|
14
|
-
* Flow creator for handling navigate actions.
|
|
15
|
-
*
|
|
16
|
-
* Execution flow:
|
|
17
|
-
* 1. Filters for navigate actions
|
|
18
|
-
* 2. Resolves the target path from the action payload
|
|
19
|
-
* 3. Creates a location object with the resolved path, key (from action meta), and optional state
|
|
20
|
-
* 4. Checks if the new location is the same as current to prevent navigation loops
|
|
21
|
-
* 5. Updates the stack based on replace option (replace updates current, otherwise pushes new entry)
|
|
22
|
-
* 6. Returns success action with the new location and appropriate action type (PUSH/REPLACE)
|
|
23
|
-
*/
|
|
24
|
-
export const navigate = (stack) => (action$) => {
|
|
25
|
-
const { navigate } = actions;
|
|
26
|
-
return action$.pipe(filterAction(navigate.type), map((action) => {
|
|
27
|
-
const { payload, meta } = action;
|
|
28
|
-
const path = resolvePath(payload.to);
|
|
29
|
-
const key = meta.key;
|
|
30
|
-
const { replace, state } = payload.options;
|
|
31
|
-
const nextLocation = { ...path, key, state, unstable_mask: undefined };
|
|
32
|
-
// prevent death loop navigation
|
|
33
|
-
if (compareLocation(nextLocation, stack.current)) {
|
|
34
|
-
return actions.abortNavigate('Location is the same as the current location');
|
|
35
|
-
}
|
|
36
|
-
if (replace) {
|
|
37
|
-
stack.replace(nextLocation);
|
|
38
|
-
}
|
|
39
|
-
else {
|
|
40
|
-
stack.push(nextLocation);
|
|
41
|
-
}
|
|
42
|
-
return navigate.success({
|
|
43
|
-
delta: 0,
|
|
44
|
-
action: replace ? Action.Replace : Action.Push,
|
|
45
|
-
location: nextLocation,
|
|
46
|
-
});
|
|
47
|
-
}));
|
|
48
|
-
};
|
|
49
|
-
/**
|
|
50
|
-
* Flow creator for handling go (back/forward) actions.
|
|
51
|
-
*
|
|
52
|
-
* Execution flow:
|
|
53
|
-
* 1. Filters for go actions
|
|
54
|
-
* 2. Combines with current state to get history entries
|
|
55
|
-
* 3. Moves the stack index by the specified delta (negative for back, positive for forward)
|
|
56
|
-
* 4. Returns success action with POP action type and the new current location
|
|
57
|
-
*/
|
|
58
|
-
export const go = (stack) => (action$, state$) => {
|
|
59
|
-
const { go } = actions;
|
|
60
|
-
return action$.pipe(filterAction(go.type), withLatestFrom(state$), map(([action, state]) => {
|
|
61
|
-
const { delta } = action.payload;
|
|
62
|
-
stack.go(delta, state);
|
|
63
|
-
return go.success({
|
|
64
|
-
delta: 0,
|
|
65
|
-
action: Action.Pop,
|
|
66
|
-
location: stack.current,
|
|
67
|
-
});
|
|
68
|
-
}));
|
|
69
|
-
};
|
|
70
|
-
/**
|
|
71
|
-
* Flow creator for handling pop (browser back/forward) actions.
|
|
72
|
-
*
|
|
73
|
-
* Execution flow:
|
|
74
|
-
* 1. Filters for pop actions
|
|
75
|
-
* 2. Uses the location from the action payload or falls back to stack.current
|
|
76
|
-
* 3. Emits a success action with POP action type and the current location
|
|
77
|
-
* 4. Completes the observable immediately (synchronous operation)
|
|
78
|
-
*/
|
|
79
|
-
export const pop = (stack) => (action$) => {
|
|
80
|
-
const { pop } = actions;
|
|
81
|
-
return action$.pipe(filterAction(pop.type), concatMap((action) => new Observable((subscriber) => {
|
|
82
|
-
const currentLocation = action.payload.update?.location ?? stack.current;
|
|
83
|
-
// todo - we might need to check if the current location is in the history stack
|
|
84
|
-
// for now we will just use the current location
|
|
85
|
-
subscriber.next(pop.success({
|
|
86
|
-
delta: 0,
|
|
87
|
-
action: Action.Pop,
|
|
88
|
-
location: currentLocation,
|
|
89
|
-
}));
|
|
90
|
-
subscriber.complete();
|
|
91
|
-
})));
|
|
92
|
-
};
|
|
93
|
-
/**
|
|
94
|
-
* Flow creator for checking navigation blockers before processing actions.
|
|
95
|
-
*
|
|
96
|
-
* Execution flow:
|
|
97
|
-
* 1. Filters for navigation actions (navigate, go, pop, validateLocation)
|
|
98
|
-
* 2. Determines the action type (PUSH/REPLACE for navigate, POP for others)
|
|
99
|
-
* 3. Combines with current state to check for active blockers
|
|
100
|
-
* 4. If no blockers exist, passes the action through immediately
|
|
101
|
-
* 5. If blockers exist:
|
|
102
|
-
* - Creates a transition object with action, location, and retry callback
|
|
103
|
-
* - Calls each blocker asynchronously (wrapped in Promise to prevent blocking)
|
|
104
|
-
* - Blockers can call retry() to allow navigation or prevent it by not calling retry()
|
|
105
|
-
* - Waits for all blockers to complete before continuing
|
|
106
|
-
* 6. Returns the original action if navigation is allowed, or completes without emitting if blocked
|
|
107
|
-
*/
|
|
108
|
-
export const checkBlockers = (stack) => (action$, state$) => {
|
|
109
|
-
const { pop, navigate, go, validateLocation } = actions;
|
|
110
|
-
return action$.pipe(filterAction(navigate.type, pop.type, go.type, validateLocation.type), map((action) => {
|
|
111
|
-
switch (action.type) {
|
|
112
|
-
case navigate.type:
|
|
113
|
-
return {
|
|
114
|
-
replace: action.payload.options.replace,
|
|
115
|
-
action: action,
|
|
116
|
-
};
|
|
117
|
-
case go.type:
|
|
118
|
-
case pop.type:
|
|
119
|
-
case validateLocation.type:
|
|
120
|
-
return {
|
|
121
|
-
type: 'POP',
|
|
122
|
-
action: action,
|
|
123
|
-
};
|
|
124
|
-
}
|
|
125
|
-
}), withLatestFrom(state$), concatMap(([{ action, replace }, state]) => {
|
|
126
|
-
if (!state.blockers.length) {
|
|
127
|
-
return of(action);
|
|
128
|
-
}
|
|
129
|
-
return new Observable((subscriber) => {
|
|
130
|
-
const location = stack.current;
|
|
131
|
-
const blockers = state.blockers.map((blocker) => Promise.resolve(blocker({
|
|
132
|
-
delta: 0,
|
|
133
|
-
action: replace ? Action.Replace : Action.Push,
|
|
134
|
-
location,
|
|
135
|
-
retry: () => {
|
|
136
|
-
subscriber.next(action);
|
|
137
|
-
},
|
|
138
|
-
})));
|
|
139
|
-
Promise.allSettled(blockers).then(() => {
|
|
140
|
-
subscriber.complete();
|
|
141
|
-
});
|
|
142
|
-
});
|
|
143
|
-
}));
|
|
144
|
-
};
|
|
145
|
-
/**
|
|
146
|
-
* Flow creator for validating the current location against history state.
|
|
147
|
-
*
|
|
148
|
-
* Execution flow:
|
|
149
|
-
* 1. Filters for validateLocation actions
|
|
150
|
-
* 2. Combines with current state to access history entries
|
|
151
|
-
* 3. Gets the current location from the stack
|
|
152
|
-
* 4. Searches history for an entry matching the current location's key
|
|
153
|
-
* 5. Validates that:
|
|
154
|
-
* - The location key exists in history (returns failure if not found)
|
|
155
|
-
* - The location state matches the history entry state (returns failure if mismatch)
|
|
156
|
-
* 6. Returns success action with current location if validation passes, failure otherwise
|
|
157
|
-
*/
|
|
158
|
-
export const validateCurrentLocation = (stack) => (action$, state$) => {
|
|
159
|
-
const { validateLocation } = actions;
|
|
160
|
-
return action$.pipe(filterAction(validateLocation.type), withLatestFrom(state$), map(([, state]) => {
|
|
161
|
-
const currentLocation = stack.current;
|
|
162
|
-
const record = state.history.find(({ location }) => location?.key === currentLocation?.key);
|
|
163
|
-
if (!record) {
|
|
164
|
-
return validateLocation.failure(new Error('Stack state not found'));
|
|
165
|
-
}
|
|
166
|
-
if (record?.location?.state !== currentLocation?.state) {
|
|
167
|
-
return validateLocation.failure(new Error('Stack state mismatch'));
|
|
168
|
-
}
|
|
169
|
-
return validateLocation.success({
|
|
170
|
-
delta: 0,
|
|
171
|
-
action: Action.Pop,
|
|
172
|
-
location: currentLocation,
|
|
173
|
-
});
|
|
174
|
-
}));
|
|
175
|
-
};
|
|
176
|
-
/**
|
|
177
|
-
* Creates a combined history flow from multiple flow creators.
|
|
178
|
-
*
|
|
179
|
-
* Merges all provided flows so they process actions in parallel.
|
|
180
|
-
* Optionally prepends a blocker-checking step that gates navigation
|
|
181
|
-
* actions through registered {@link NavigationBlocker | blockers}.
|
|
182
|
-
*
|
|
183
|
-
* @param flowCreators - Array of flow creators to combine
|
|
184
|
-
* @param options - Optional configuration
|
|
185
|
-
* @param options.skipBlockCheck - If `true`, skip blocker checking
|
|
186
|
-
* @returns A combined {@link HistoryFlowCreator} that merges all provided flows
|
|
187
|
-
*/
|
|
188
|
-
export const createFlow = (flowCreators, options) => {
|
|
189
|
-
return (stack) => {
|
|
190
|
-
const preProcessActions = options?.skipBlockCheck
|
|
191
|
-
? (action$) => action$
|
|
192
|
-
: checkBlockers(stack);
|
|
193
|
-
const flows = (action$, state$) => {
|
|
194
|
-
return merge(...flowCreators
|
|
195
|
-
.map((initializer) => initializer(stack))
|
|
196
|
-
.map((flow) => flow(action$, state$)));
|
|
197
|
-
};
|
|
198
|
-
return (action$, state$) => {
|
|
199
|
-
return preProcessActions(action$, state$).pipe((source$) => flows(source$, state$));
|
|
200
|
-
};
|
|
201
|
-
};
|
|
202
|
-
};
|
|
203
|
-
/**
|
|
204
|
-
* Collection of flow creators for history state management.
|
|
205
|
-
*/
|
|
206
|
-
export const flowCreators = { navigate, go, pop, validateCurrentLocation };
|
|
207
|
-
//# sourceMappingURL=history.flows.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"history.flows.js","sourceRoot":"","sources":["../../../../src/lib/state/history.flows.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"history.reducer.js","sourceRoot":"","sources":["../../../../src/lib/state/history.reducer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,4BAA4B,CAAC;AAE3D,OAAO,EAAE,OAAO,EAAgB,MAAM,mBAAmB,CAAC;AAC1D,OAAO,EAAE,eAAe,EAAE,MAAM,oCAAoC,CAAC;AAErE;;;GAGG;AACH,MAAM,SAAS,GAAG,CAAC,KAAoB,EAAE,EAAE;IACzC,OAAO,KAAK,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,QAAQ,CAAC,GAAG,KAAK,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC;AACjG,CAAC,CAAC;AAEF;;;;;;;;;;;GAWG;AACH,MAAM,CAAC,MAAM,oBAAoB,GAAG,CAClC,OAAiD,EACjD,OAAiC,EACjC,EAAE;IACF,MAAM,UAAU,GAAG,OAAO,EAAE,UAAU,IAAI,GAAG,CAAC;IAE9C,MAAM,YAAY,GAChB,OAAO,YAAY,QAAQ;QACzB,CAAC,CAAC,OAAO,EAAE;QACX,CAAC,CAAE;YACC,OAAO,EAAE,OAAO;YAChB,OAAO,EAAE,CAAC,OAAO,CAAC;YAClB,QAAQ,EAAE,EAAE;SACY,CAAC;IAEjC,OAAO,aAAa,CAAyB,YAAY,EAAE,CAAC,OAAO,EAAE,EAAE;QACrE,0DAA0D;QAC1D,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,QAAQ,CAAC,OAAO,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE;YAC1D,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,CAAC,OAAO,CAAC;YAClC,gFAAgF;YAChF,sEAAsE;YACtE,sDAAsD;YACtD,IAAI,MAAM,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC;gBAChC,MAAM,YAAY,GAAG,SAAS,CAAC,KAAK,CAAC,CAAC;gBACtC,IAAI,YAAY,KAAK,CAAC,CAAC,EAAE,CAAC;oBACxB,mDAAmD;oBACnD,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,YAAY,EAAE,KAAK,CAAC,OAAO,CAAC,MAAM,GAAG,YAAY,CAAC,CAAC;gBAC1E,CAAC;YACH,CAAC;YACD,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QAC7B,CAAC,CAAC,CAAC;QACH,+EAA+E;QAC/E,OAAO,CAAC,UAAU,CAAC,eAAe,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE;YACpD,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,CAAC,OAAO,CAAC;YAClC,KAAK,CAAC,OAAO,GAAG,MAAM,CAAC;QACzB,CAAC,CAAC,CAAC;QACH,iDAAiD;QACjD,qFAAqF;QACrF,OAAO,CAAC,UAAU,CAChB,GAAG,EAAE,CAAC,IAAI,EACV,CAAC,KAAK,EAAE,EAAE;YACR,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,GAAG,UAAU,EAAE,CAAC;gBACtC,0DAA0D;gBAC1D,KAAK,CAAC,OAAO,GAAG,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,UAAU,CAAC,CAAC;YACnD,CAAC;QACH,CAAC,CACF,CAAC;IACJ,CAAC,CAAC,CAAC;AACL,CAAC,CAAC"}
|