1 | import {
|
2 | CommonActions,
|
3 | NavigationAction,
|
4 | NavigationState,
|
5 | ParamListBase,
|
6 | Router,
|
7 | } from '@react-navigation/routers';
|
8 | import * as React from 'react';
|
9 |
|
10 | import NavigationContext from './NavigationContext';
|
11 | import { NavigationHelpers, PrivateValueStore } from './types';
|
12 | import UnhandledActionContext from './UnhandledActionContext';
|
13 | import type { NavigationEventEmitter } from './useEventEmitter';
|
14 |
|
15 |
|
16 |
|
17 | PrivateValueStore;
|
18 |
|
19 | type Options<State extends NavigationState, Action extends NavigationAction> = {
|
20 | id: string | undefined;
|
21 | onAction: (action: NavigationAction) => boolean;
|
22 | getState: () => State;
|
23 | emitter: NavigationEventEmitter<any>;
|
24 | router: Router<State, Action>;
|
25 | };
|
26 |
|
27 |
|
28 |
|
29 |
|
30 |
|
31 | export default function useNavigationHelpers<
|
32 | State extends NavigationState,
|
33 | ActionHelpers extends Record<string, () => void>,
|
34 | Action extends NavigationAction,
|
35 | EventMap extends Record<string, any>
|
36 | >({
|
37 | id: navigatorId,
|
38 | onAction,
|
39 | getState,
|
40 | emitter,
|
41 | router,
|
42 | }: Options<State, Action>) {
|
43 | const onUnhandledAction = React.useContext(UnhandledActionContext);
|
44 | const parentNavigationHelpers = React.useContext(NavigationContext);
|
45 |
|
46 | return React.useMemo(() => {
|
47 | const dispatch = (op: Action | ((state: State) => Action)) => {
|
48 | const action = typeof op === 'function' ? op(getState()) : op;
|
49 |
|
50 | const handled = onAction(action);
|
51 |
|
52 | if (!handled) {
|
53 | onUnhandledAction?.(action);
|
54 | }
|
55 | };
|
56 |
|
57 | const actions = {
|
58 | ...router.actionCreators,
|
59 | ...CommonActions,
|
60 | };
|
61 |
|
62 | const helpers = Object.keys(actions).reduce((acc, name) => {
|
63 |
|
64 | acc[name] = (...args: any) => dispatch(actions[name](...args));
|
65 | return acc;
|
66 | }, {} as ActionHelpers);
|
67 |
|
68 | const navigationHelpers = {
|
69 | ...parentNavigationHelpers,
|
70 | ...helpers,
|
71 | dispatch,
|
72 | emit: emitter.emit,
|
73 | isFocused: parentNavigationHelpers
|
74 | ? parentNavigationHelpers.isFocused
|
75 | : () => true,
|
76 | canGoBack: () => {
|
77 | const state = getState();
|
78 |
|
79 | return (
|
80 | router.getStateForAction(state, CommonActions.goBack() as Action, {
|
81 | routeNames: state.routeNames,
|
82 | routeParamList: {},
|
83 | routeGetIdList: {},
|
84 | }) !== null ||
|
85 | parentNavigationHelpers?.canGoBack() ||
|
86 | false
|
87 | );
|
88 | },
|
89 | getId: () => navigatorId,
|
90 | getParent: (id?: string) => {
|
91 | if (id !== undefined) {
|
92 | let current = navigationHelpers;
|
93 |
|
94 | while (current && id !== current.getId()) {
|
95 | current = current.getParent();
|
96 | }
|
97 |
|
98 | return current;
|
99 | }
|
100 |
|
101 | return parentNavigationHelpers;
|
102 | },
|
103 | getState,
|
104 | } as NavigationHelpers<ParamListBase, EventMap> & ActionHelpers;
|
105 |
|
106 | return navigationHelpers;
|
107 | }, [
|
108 | navigatorId,
|
109 | emitter.emit,
|
110 | getState,
|
111 | onAction,
|
112 | onUnhandledAction,
|
113 | parentNavigationHelpers,
|
114 | router,
|
115 | ]);
|
116 | }
|