@exponent/ex-navigation
Version:
Route-centric navigation library for React Native.
215 lines (187 loc) • 5.56 kB
JavaScript
/**
* @flow
*/
import invariant from 'invariant';
import Actions from './ExNavigationActions';
import createNavigationStore, { batchNavigationActions } from './ExNavigationStore';
// import ExNavigationVisibilityManager from 'ExNavigationVisibilityManager';
import type ExNavigatorContext from './ExNavigatorContext';
import type {
ExNavigationRoute,
ExNavigationRouter,
} from './ExNavigationRouter';
import type {
ExNavigationStore,
ExNavigationState,
} from './ExNavigationStore';
/**
* Represents
*/
export default class NavigationContext {
_store: ExNavigationStore;
_router: ExNavigationRouter<*>;
_navigatorContexts: {
[navigatorUID: string]: ExNavigatorContext<*>
};
// _visiblityManager: ExNavigationVisibilityManager;
registerNavigatorContext: (navigatorUID: string, navigatorContext: ExNavigatorContext<*>) => void;
constructor({ store, router }: { store?: ExNavigationStore, router: ExNavigationRouter<*> }) {
if (store == null) {
store = createNavigationStore();
}
this._store = store;
this._router = router;
this._navigatorContexts = {};
}
getNavigator(navigatorId: string): ExNavigatorContext<*> {
let navigatorContext;
const contextKeys = Object.keys(this._navigatorContexts);
contextKeys.forEach(contextKey => {
let c = this._navigatorContexts[contextKey];
if (c.navigatorId === navigatorId) {
if (!navigatorContext) {
navigatorContext = c;
} else {
throw new Error(`More than one navigator exists with id '${navigatorId}'. Please access the navigator context using 'getNavigatorByUID'.`);
}
}
});
invariant(navigatorContext, 'Navigator does not exist.');
return navigatorContext;
}
/**
* Returns the NavigatorContext for the specified navigator.
*/
getNavigatorByUID(navigatorUID: string): ExNavigatorContext<*> {
// return the NavigatorContext for navigatorId
invariant(this._navigatorContexts[navigatorUID], 'Navigator does not exist.');
return this._navigatorContexts[navigatorUID];
}
getCurrentNavigatorUID(): ?string {
const state = this.navigationState;
if (state) {
return state.currentNavigatorUID;
}
return null;
}
getFocusedRoute(): ?ExNavigationRoute {
if (!this.navigationState) {
return null;
}
const currentNavigator = this.navigationState.navigators[this.navigationState.currentNavigatorUID];
if (!currentNavigator) {
return null;
}
return currentNavigator.routes[currentNavigator.index];
}
registerNavigatorContext = (navigatorUID: string, navigatorContext: ExNavigatorContext<*>) => {
this._navigatorContexts[navigatorUID] = navigatorContext;
}
unregisterNavigatorContext = (navigatorUID: string) => {
delete this._navigatorContexts[navigatorUID];
}
get store(): ExNavigationStore {
return this._store;
}
get navigationStateKey(): string {
return this._store.__exNavigationStateKey;
}
get dispatch(): (action: mixed) => any {
if (!this._store) {
throw new Error('Store is not set on navigation context.');
}
return this._store.dispatch;
}
get router(): ExNavigationRouter<*> {
return this._router;
}
get navigationState(): ?ExNavigationState {
const state = this._store.getState();
if (state == null) {
return null;
}
return state[this._store.__exNavigationStateKey];
}
performAction(actionFn: Function) {
let actions = [];
const stateUtils = {
drawer: (uid) => ({
jumpToItem: (itemId) => {
actions.push(
Actions.jumpToItem(uid, {
key: itemId,
})
);
},
toggleDrawer: () => {
actions.push(
Actions.toggleDrawer(uid)
);
},
}),
tabs: (uid) => ({
jumpToTab: (tabId) => {
actions.push(
Actions.jumpToTab(uid, {
key: tabId,
})
);
},
}),
stacks: (uid) => ({
push: (route) => {
actions.push(
Actions.push(uid, route)
);
},
pop: (n = 1) => {
if (n === 1) {
actions.push(
Actions.pop(uid)
);
} else {
actions.push(
Actions.popN(uid, n)
);
}
},
popToTop: () => {
actions.push(
Actions.popToTop(uid)
);
},
replace: (route) => {
actions.push(
Actions.replace(uid, route)
);
},
immediatelyResetStack: (routes, index) => {
const mappedChildren = routes.map((route, i) => {
invariant(route !== null && route.key, `Route at index ${i} is null or malformed.`);
return route;
});
actions.push(
Actions.immediatelyResetStack(uid, mappedChildren, index)
);
},
updateCurrentRouteParams: (newParams) => {
actions.push(
Actions.updateCurrentRouteParams(uid, newParams)
);
},
showLocalAlert: (message, options) => {
actions.push(
Actions.showLocalAlert(uid, message, options)
);
},
hideLocalAlert: () => {
actions.push(
Actions.hideLocalAlert(uid)
);
},
}),
};
actionFn(stateUtils);
this.store.dispatch(batchNavigationActions(actions));
}
}