NavigationExperimental: Add documentation for NavigationStateUtils.

Summary: Add docs to NavigationStateUtils.

Reviewed By: ericvicenti

Differential Revision: D3679295

fbshipit-source-id: 26fc1e4f39af58e11572b74b150e08b3094e36c6
This commit is contained in:
Hedger Wang 2016-08-14 23:07:23 -07:00 committed by Facebook Github Bot 4
parent e106a4f094
commit 3a8c302ae8
1 changed files with 178 additions and 188 deletions

View File

@ -15,211 +15,201 @@ const invariant = require('fbjs/lib/invariant');
import type {
NavigationRoute,
NavigationState,
NavigationState
} from 'NavigationTypeDefinition';
/**
* Utilities to perform atomic operation with navigate state and routes.
*
* ```javascript
* const state1 = {key: 'page 1'};
* const state2 = NavigationStateUtils.push(state1, {key: 'page 2'});
* ```
*/
const NavigationStateUtils = {
/**
* Gets a route by key
*/
function get(state: NavigationState, key: string): ?NavigationRoute {
return state.routes.find(route => route.key === key) || null;
}
/**
* Gets a route by key. If the route isn't found, returns `null`.
*/
get(state: NavigationState, key: string): ?NavigationRoute {
return state.routes.find(route => route.key === key) || null;
},
/**
* Returns the first index at which a given route's key can be found in the
* routes of the navigation state, or -1 if it is not present.
*/
function indexOf(state: NavigationState, key: string): number {
return state.routes.map(route => route.key).indexOf(key);
}
/**
* Returns the first index at which a given route's key can be found in the
* routes of the navigation state, or -1 if it is not present.
*/
indexOf(state: NavigationState, key: string): number {
return state.routes.map(route => route.key).indexOf(key);
},
/**
* Returns `true` at which a given route's key can be found in the
* routes of the navigation state.
*/
function has(state: NavigationState, key: string): boolean {
return !!state.routes.some(route => route.key === key);
}
/**
* Returns `true` at which a given route's key can be found in the
* routes of the navigation state.
*/
has(state: NavigationState, key: string): boolean {
return !!state.routes.some(route => route.key === key);
},
/**
* Pushes a new route into the navigation state.
* Note that this moves the index to the positon to where the last route in the
* stack is at.
*/
function push(state: NavigationState, route: NavigationRoute): NavigationState {
invariant(
indexOf(state, route.key) === -1,
'should not push route with duplicated key %s',
route.key,
);
/**
* Pushes a new route into the navigation state.
* Note that this moves the index to the positon to where the last route in the
* stack is at.
*/
push(state: NavigationState, route: NavigationRoute): NavigationState {
invariant(
NavigationStateUtils.indexOf(state, route.key) === -1,
'should not push route with duplicated key %s',
route.key,
);
const routes = [
...state.routes,
route,
];
const routes = state.routes.slice();
routes.push(route);
return {
...state,
index: routes.length - 1,
routes,
};
}
return {
...state,
index: routes.length - 1,
routes,
};
},
/**
* Pops out a route from the navigation state.
* Note that this moves the index to the positon to where the last route in the
* stack is at.
*/
function pop(state: NavigationState): NavigationState {
if (state.index <= 0) {
// [Note]: Over-popping does not throw error. Instead, it will be no-op.
return state;
}
const routes = state.routes.slice(0, -1);
return {
...state,
index: routes.length - 1,
routes,
};
}
/**
* Sets the focused route of the navigation state by index.
*/
function jumpToIndex(state: NavigationState, index: number): NavigationState {
if (index === state.index) {
return state;
}
invariant(!!state.routes[index], 'invalid index %s to jump to', index);
return {
...state,
index,
};
}
/**
* Sets the focused route of the navigation state by key.
*/
function jumpTo(state: NavigationState, key: string): NavigationState {
const index = indexOf(state, key);
return jumpToIndex(state, index);
}
/**
* Sets the focused route to the previous route.
*/
function back(state: NavigationState): NavigationState {
const index = state.index - 1;
const route = state.routes[index];
return route ? jumpToIndex(state, index) : state;
}
/**
* Sets the focused route to the next route.
*/
function forward(state: NavigationState): NavigationState {
const index = state.index + 1;
const route = state.routes[index];
return route ? jumpToIndex(state, index) : state;
}
/**
* Replace a route by a key.
* Note that this moves the index to the positon to where the new route in the
* stack is at.
*/
function replaceAt(
state: NavigationState,
key: string,
route: NavigationRoute,
): NavigationState {
const index = indexOf(state, key);
return replaceAtIndex(state, index, route);
}
/**
* Replace a route by a index.
* Note that this moves the index to the positon to where the new route in the
* stack is at.
*/
function replaceAtIndex(
state: NavigationState,
index: number,
route: NavigationRoute,
): NavigationState {
invariant(
!!state.routes[index],
'invalid index %s for replacing route %s',
index,
route.key,
);
if (state.routes[index] === route) {
return state;
}
const routes = state.routes.slice();
routes[index] = route;
return {
...state,
index,
routes,
};
}
/**
* Resets all routes.
* Note that this moves the index to the positon to where the last route in the
* stack is at if the param `index` isn't provided.
*/
function reset(
state: NavigationState,
routes: Array<NavigationRoute>,
index?: number,
): NavigationState {
invariant(
routes.length && Array.isArray(routes),
'invalid routes to replace',
);
const nextIndex: number = index === undefined ? routes.length - 1 : index;
if (state.routes.length === routes.length && state.index === nextIndex) {
const compare = (route, ii) => routes[ii] === route;
if (state.routes.every(compare)) {
/**
* Pops out a route from the navigation state.
* Note that this moves the index to the positon to where the last route in the
* stack is at.
*/
pop(state: NavigationState): NavigationState {
if (state.index <= 0) {
// [Note]: Over-popping does not throw error. Instead, it will be no-op.
return state;
}
}
const routes = state.routes.slice(0, -1);
return {
...state,
index: routes.length - 1,
routes,
};
},
invariant(!!routes[nextIndex], 'invalid index %s to reset', nextIndex);
/**
* Sets the focused route of the navigation state by index.
*/
jumpToIndex(state: NavigationState, index: number): NavigationState {
if (index === state.index) {
return state;
}
return {
...state,
index: nextIndex,
routes,
};
}
invariant(!!state.routes[index], 'invalid index %s to jump to', index);
const NavigationStateUtils = {
back,
forward,
get: get,
has,
indexOf,
jumpTo,
jumpToIndex,
pop,
push,
replaceAt,
replaceAtIndex,
reset,
return {
...state,
index,
};
},
/**
* Sets the focused route of the navigation state by key.
*/
jumpTo(state: NavigationState, key: string): NavigationState {
const index = NavigationStateUtils.indexOf(state, key);
return NavigationStateUtils.jumpToIndex(state, index);
},
/**
* Sets the focused route to the previous route.
*/
back(state: NavigationState): NavigationState {
const index = state.index - 1;
const route = state.routes[index];
return route ? NavigationStateUtils.jumpToIndex(state, index) : state;
},
/**
* Sets the focused route to the next route.
*/
forward(state: NavigationState): NavigationState {
const index = state.index + 1;
const route = state.routes[index];
return route ? NavigationStateUtils.jumpToIndex(state, index) : state;
},
/**
* Replace a route by a key.
* Note that this moves the index to the positon to where the new route in the
* stack is at.
*/
replaceAt(
state: NavigationState,
key: string,
route: NavigationRoute,
): NavigationState {
const index = NavigationStateUtils.indexOf(state, key);
return NavigationStateUtils.replaceAtIndex(state, index, route);
},
/**
* Replace a route by a index.
* Note that this moves the index to the positon to where the new route in the
* stack is at.
*/
replaceAtIndex(
state: NavigationState,
index: number,
route: NavigationRoute,
): NavigationState {
invariant(
!!state.routes[index],
'invalid index %s for replacing route %s',
index,
route.key,
);
if (state.routes[index] === route) {
return state;
}
const routes = state.routes.slice();
routes[index] = route;
return {
...state,
index,
routes,
};
},
/**
* Resets all routes.
* Note that this moves the index to the positon to where the last route in the
* stack is at if the param `index` isn't provided.
*/
reset(
state: NavigationState,
routes: Array<NavigationRoute>,
index?: number,
): NavigationState {
invariant(
routes.length && Array.isArray(routes),
'invalid routes to replace',
);
const nextIndex: number = index === undefined ? routes.length - 1 : index;
if (state.routes.length === routes.length && state.index === nextIndex) {
const compare = (route, ii) => routes[ii] === route;
if (state.routes.every(compare)) {
return state;
}
}
invariant(!!routes[nextIndex], 'invalid index %s to reset', nextIndex);
return {
...state,
index: nextIndex,
routes,
};
},
};
module.exports = NavigationStateUtils;