Skip to content
This repository has been archived by the owner on Feb 8, 2020. It is now read-only.

Commit

Permalink
feat: add a target key to actions and various fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
satya164 committed Aug 6, 2019
1 parent d02277b commit 747ce66
Show file tree
Hide file tree
Showing 9 changed files with 135 additions and 5 deletions.
10 changes: 9 additions & 1 deletion packages/core/src/BaseActions.tsx
Original file line number Diff line number Diff line change
@@ -1,28 +1,36 @@
import { PartialState, NavigationState, TargetRoute } from './types';

export type Action =
| { type: 'GO_BACK'; source?: string }
| {
type: 'GO_BACK';
source?: string;
target?: string;
}
| {
type: 'NAVIGATE';
payload:
| { name: string; key?: undefined; params?: object }
| { key: string; name?: undefined; params?: object };
source?: string;
target?: string;
}
| {
type: 'REPLACE';
payload: { name: string; params?: object };
source?: string;
target?: string;
}
| {
type: 'RESET';
payload: PartialState<NavigationState> & { key?: string };
source?: string;
target?: string;
}
| {
type: 'SET_PARAMS';
payload: { key?: string; params?: object };
source?: string;
target?: string;
};

export function goBack(): Action {
Expand Down
85 changes: 85 additions & 0 deletions packages/core/src/__tests__/useOnAction.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,91 @@ it("lets children handle the action if parent didn't", () => {
});
});

it("action doesn't bubble if target is specified", () => {
const CurrentParentRouter = MockRouter;

function CurrentChildRouter(options: DefaultRouterOptions) {
const CurrentMockRouter = MockRouter(options);
const ChildRouter: Router<
NavigationState,
MockActions | { type: 'REVERSE' }
> = {
...CurrentMockRouter,

shouldActionChangeFocus() {
return true;
},

getStateForAction(state, action) {
if (action.type === 'REVERSE') {
return {
...state,
routes: state.routes.slice().reverse(),
};
}

return CurrentMockRouter.getStateForAction(state, action);
},
};
return ChildRouter;
}

const ChildNavigator = (props: any) => {
const { state, descriptors } = useNavigationBuilder(
CurrentChildRouter,
props
);

return descriptors[state.routes[state.index].key].render();
};

const ParentNavigator = (props: any) => {
const { state, descriptors } = useNavigationBuilder(
CurrentParentRouter,
props
);

return (
<React.Fragment>
{state.routes.map(route => descriptors[route.key].render())}
</React.Fragment>
);
};

const TestScreen = (props: any) => {
React.useEffect(() => {
props.navigation.dispatch({ type: 'REVERSE', target: '0' });

// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);

return null;
};

const onStateChange = jest.fn();

const element = (
<NavigationContainer onStateChange={onStateChange}>
<ParentNavigator>
<Screen name="foo">{() => null}</Screen>
<Screen name="bar" component={TestScreen} />
<Screen name="baz">
{() => (
<ChildNavigator>
<Screen name="qux" component={() => null} />
<Screen name="lex" component={() => null} />
</ChildNavigator>
)}
</Screen>
</ParentNavigator>
</NavigationContainer>
);

render(element).update(element);

expect(onStateChange).not.toBeCalled();
});

it("doesn't crash if no navigator handled the action", () => {
const TestRouter = MockRouter;

Expand Down
4 changes: 4 additions & 0 deletions packages/core/src/index.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
import * as BaseActions from './BaseActions';

export { BaseActions };

export { default as BaseRouter } from './BaseRouter';
export { default as NavigationContainer } from './NavigationContainer';
export { default as createNavigator } from './createNavigator';
Expand Down
1 change: 1 addition & 0 deletions packages/core/src/types.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ export type Route<RouteName extends string> = {
export type NavigationAction = {
type: string;
source?: string;
target?: string;
};

export type ActionCreators<Action extends NavigationAction> = {
Expand Down
4 changes: 3 additions & 1 deletion packages/core/src/useNavigationHelpers.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { NavigationStateContext } from './NavigationContainer';
import { NavigationEventEmitter } from './useEventEmitter';
import {
NavigationHelpers,
NavigationProp,
NavigationAction,
NavigationState,
ActionCreators,
Expand Down Expand Up @@ -32,7 +33,8 @@ export default function useNavigationHelpers<Action extends NavigationAction>({
const parentNavigationHelpers = React.useContext(NavigationContext);
const { performTransaction } = React.useContext(NavigationStateContext);

return React.useMemo((): NavigationHelpers<ParamListBase> => {
return React.useMemo((): NavigationHelpers<ParamListBase> &
Partial<NavigationProp<ParamListBase, string, any, any, any>> => {
const dispatch = (
action: NavigationAction | ((state: NavigationState) => NavigationState)
) => {
Expand Down
6 changes: 5 additions & 1 deletion packages/core/src/useOnAction.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,11 @@ export default function useOnAction({
visitedNavigators.add(state.key);

if (targetForInternalDispatching === undefined) {
const result = router.getStateForAction(state, action);
let result = router.getStateForAction(state, action);

// If a target is specified and set to current navigator, the action shouldn't bubble
result =
result === null && action.target === state.key ? state : result;

if (result !== null) {
if (state !== result) {
Expand Down
19 changes: 19 additions & 0 deletions packages/routers/src/DrawerRouter.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ export type DrawerActionType =
| {
type: 'OPEN_DRAWER' | 'CLOSE_DRAWER' | 'TOGGLE_DRAWER';
source?: string;
target?: string;
};

export type DrawerRouterOptions = TabRouterOptions;
Expand Down Expand Up @@ -67,6 +68,24 @@ export default function DrawerRouter(
};
},

getStateForRouteFocus(state, key) {
const index = state.routes.findIndex(r => r.key === key);

const result =
index === -1 || index === state.index
? state
: router.getStateForRouteFocus(state, key);

if (result.isDrawerOpen) {
return {
...result,
isDrawerOpen: false,
};
}

return result;
},

getStateForAction(state, action) {
switch (action.type) {
case 'OPEN_DRAWER':
Expand Down
10 changes: 8 additions & 2 deletions packages/routers/src/StackRouter.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,19 @@ export type StackActionType =
type: 'PUSH';
payload: { name: string; params?: object };
source?: string;
target?: string;
}
| {
type: 'POP';
payload: { count: number };
source?: string;
target?: string;
}
| { type: 'POP_TO_TOP'; source?: string };
| {
type: 'POP_TO_TOP';
source?: string;
target?: string;
};

export type StackRouterOptions = DefaultRouterOptions;

Expand Down Expand Up @@ -129,7 +135,7 @@ export default function StackRouter(options: StackRouterOptions) {
if (state.index > 0 && index > -1) {
return {
...state,
index: state.index - 1,
index: Math.max(0, state.index - action.payload.count),
routes: state.routes.slice(
0,
Math.max(index - action.payload.count + 1, 1)
Expand Down
1 change: 1 addition & 0 deletions packages/routers/src/TabRouter.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ export type TabActionType = {
type: 'JUMP_TO';
payload: { name: string; params?: object };
source?: string;
target?: string;
};

export type TabRouterOptions = DefaultRouterOptions & {
Expand Down

0 comments on commit 747ce66

Please sign in to comment.