GT2/Ejectable/node_modules/@react-navigation/routers/src/DrawerRouter.tsx

213 lines
4.5 KiB
TypeScript

import { nanoid } from 'nanoid/non-secure';
import type {
PartialState,
CommonNavigationAction,
Router,
ParamListBase,
} from './types';
import TabRouter, {
TabActions,
TabActionType,
TabRouterOptions,
TabNavigationState,
TabActionHelpers,
} from './TabRouter';
export type DrawerActionType =
| TabActionType
| {
type: 'OPEN_DRAWER' | 'CLOSE_DRAWER' | 'TOGGLE_DRAWER';
source?: string;
target?: string;
};
export type DrawerRouterOptions = TabRouterOptions & {
openByDefault?: boolean;
};
export type DrawerNavigationState<ParamList extends ParamListBase> = Omit<
TabNavigationState<ParamList>,
'type' | 'history'
> & {
/**
* Type of the router, in this case, it's drawer.
*/
type: 'drawer';
/**
* List of previously visited route keys and drawer open status.
*/
history: ({ type: 'route'; key: string } | { type: 'drawer' })[];
};
export type DrawerActionHelpers<
ParamList extends ParamListBase
> = TabActionHelpers<ParamList> & {
/**
* Open the drawer sidebar.
*/
openDrawer(): void;
/**
* Close the drawer sidebar.
*/
closeDrawer(): void;
/**
* Open the drawer sidebar if closed, or close if opened.
*/
toggleDrawer(): void;
};
export const DrawerActions = {
...TabActions,
openDrawer(): DrawerActionType {
return { type: 'OPEN_DRAWER' };
},
closeDrawer(): DrawerActionType {
return { type: 'CLOSE_DRAWER' };
},
toggleDrawer(): DrawerActionType {
return { type: 'TOGGLE_DRAWER' };
},
};
const isDrawerOpen = (
state:
| DrawerNavigationState<ParamListBase>
| PartialState<DrawerNavigationState<ParamListBase>>
) => Boolean(state.history?.some((it) => it.type === 'drawer'));
const openDrawer = (
state: DrawerNavigationState<ParamListBase>
): DrawerNavigationState<ParamListBase> => {
if (isDrawerOpen(state)) {
return state;
}
return {
...state,
history: [...state.history, { type: 'drawer' }],
};
};
const closeDrawer = (
state: DrawerNavigationState<ParamListBase>
): DrawerNavigationState<ParamListBase> => {
if (!isDrawerOpen(state)) {
return state;
}
return {
...state,
history: state.history.filter((it) => it.type !== 'drawer'),
};
};
export default function DrawerRouter({
openByDefault,
...rest
}: DrawerRouterOptions): Router<
DrawerNavigationState<ParamListBase>,
DrawerActionType | CommonNavigationAction
> {
const router = (TabRouter(rest) as unknown) as Router<
DrawerNavigationState<ParamListBase>,
TabActionType | CommonNavigationAction
>;
return {
...router,
type: 'drawer',
getInitialState({ routeNames, routeParamList, routeGetIdList }) {
let state = router.getInitialState({
routeNames,
routeParamList,
routeGetIdList,
});
if (openByDefault) {
state = openDrawer(state);
}
return {
...state,
stale: false,
type: 'drawer',
key: `drawer-${nanoid()}`,
};
},
getRehydratedState(
partialState,
{ routeNames, routeParamList, routeGetIdList }
) {
if (partialState.stale === false) {
return partialState;
}
let state = router.getRehydratedState(partialState, {
routeNames,
routeParamList,
routeGetIdList,
});
if (partialState.history ? isDrawerOpen(partialState) : openByDefault) {
state = openDrawer(state);
}
return {
...state,
type: 'drawer',
key: `drawer-${nanoid()}`,
};
},
getStateForRouteFocus(state, key) {
const result = router.getStateForRouteFocus(state, key);
if (openByDefault) {
return openDrawer(result);
}
return closeDrawer(result);
},
getStateForAction(state, action, options) {
switch (action.type) {
case 'OPEN_DRAWER':
return openDrawer(state);
case 'CLOSE_DRAWER':
return closeDrawer(state);
case 'TOGGLE_DRAWER':
if (isDrawerOpen(state)) {
return closeDrawer(state);
}
return openDrawer(state);
case 'GO_BACK':
if (openByDefault) {
if (!isDrawerOpen(state)) {
return openDrawer(state);
}
} else {
if (isDrawerOpen(state)) {
return closeDrawer(state);
}
}
return router.getStateForAction(state, action, options);
default:
return router.getStateForAction(state, action, options);
}
},
actionCreators: DrawerActions,
};
}