react-native-navigation
Version:
React Native Navigation - truly native navigation for iOS and Android
176 lines (174 loc) • 5.47 kB
JavaScript
;
import _ from 'lodash';
import LayoutNodeFactory from "../Layouts/LayoutNodeFactory.js";
const remx = require('remx');
const state = remx.state({
root: {},
modals: [],
overlays: [],
sideMenu: undefined
});
const setters = remx.setters({
setRoot(layout) {
state.modals = [];
state.root = layout;
},
push(layout, stack) {
stack.children.push(layout);
},
pop(layoutId) {
const stack = getters.getLayoutById(layoutId).getStack();
if (stack.children.length === 1) return;
const poppedChild = stack.children.pop();
const newVisibleChild = stack.getVisibleLayout();
poppedChild.componentDidDisappear();
newVisibleChild.componentDidAppear();
return _.clone(poppedChild.nodeId);
},
popTo(layoutId) {
const stack = getters.getLayoutById(layoutId).getStack();
while (stack.getVisibleLayout().nodeId != layoutId) {
stack.children.pop();
}
},
popToRoot(layoutId) {
const stack = getters.getLayoutById(layoutId).getStack();
while (stack.children.length > 1) {
stack.children.pop();
}
},
setStackRoot(layoutId, layout) {
const currentLayout = getters.getLayoutById(layoutId);
if (currentLayout) {
const stack = currentLayout.getStack();
stack.children = layout.map(child => LayoutNodeFactory.create(child, stack));
}
},
showOverlay(overlay) {
state.overlays.push(overlay);
},
dismissOverlay(overlayId) {
_.remove(state.overlays, overlay => overlay.nodeId === overlayId);
},
dismissAllOverlays() {
state.overlays = [];
},
showModal(modal) {
state.modals.push(modal);
},
dismissModal(componentId) {
const modal = getters.getModalById(componentId);
if (modal) {
const child = modal.getVisibleLayout();
const topParent = child.getTopParent();
_.remove(state.modals, modal => modal.nodeId === topParent.nodeId);
}
},
dismissAllModals() {
state.modals = [];
},
selectTabIndex(layout, index) {
getters.getLayoutById(layout.nodeId).selectedIndex = index;
},
openSideMenu(layout) {
if (state.sideMenu) {
throw new Error('A side-menu is already open; Mocked-testing of multiple side-menu scenarios is not supported yet.' + ' You can submit a request in https://github.com/wix/react-native-navigation/issues/new/choose.');
}
state.sideMenu = layout;
},
closeSideMenu(_layout) {
state.sideMenu = undefined;
},
applyOptions(componentId, options) {
const layout = getters.getLayoutById(componentId);
if (layout) layout.applyOptions(options);else console.warn(`[RNN error] Merge options failure: cannot find layout for: ${componentId}`);
},
mergeOptions(componentId, options) {
const layout = getters.getLayoutById(componentId);
if (layout) layout.mergeOptions(options);else console.warn(`[RNN error] Merge options failure: cannot find layout for: ${componentId}`);
}
});
const getters = remx.getters({
getLayout() {
return state.root;
},
getVisibleLayout() {
let layout;
if (state.modals.length > 0) {
layout = _.last(state.modals);
} else if (!_.isEqual(state.root, {})) {
layout = state.root;
}
// Note: While this logic should be fair for all use cases (i.e. even multiple side-menus across tabs),
// there is no current test case that justifies it. Nevertheless, it's required to pass the tests,
// because otherwise getVisibleLayout() would not be revisited whenever side-menus are opened/closed.
if (layout && state.sideMenu && findNode(state.sideMenu.nodeId, layout)) {
layout = state.sideMenu.parentNode;
}
return layout?.getVisibleLayout();
},
isVisibleLayout(layout) {
const nodeId = layout.nodeId;
const visibleLayout = getters.getVisibleLayout();
return visibleLayout?.nodeId === nodeId;
},
getModals() {
return state.modals;
},
getOverlays() {
return state.overlays;
},
getLayoutById(layoutId) {
if (getters.getModalById(layoutId)) return findNode(layoutId, getters.getModalById(layoutId));
return findNode(layoutId, state.root);
},
getModalById(layoutId) {
return _.find(state.modals, layout => findNode(layoutId, layout));
},
getLayoutChildren(layoutId) {
return getters.getLayoutById(layoutId).children;
},
getStack(layoutId) {
return findStack(layoutId, state.root) || _.find(state.modals, layout => findStack(layoutId, layout));
}
});
function findNode(layoutId, layout) {
if (layoutId === layout.nodeId) {
return layout;
} else if (layout.children) {
for (let i = 0; i < layout.children.length; i += 1) {
const child = layout.children[i];
const result = findNode(layoutId, child);
if (result !== false) {
return result;
}
}
}
return false;
}
function findStack(layoutId, layout) {
if (layout.type === 'Stack' && _.find(layout.children, child => child.nodeId === layoutId)) {
return layout;
} else if (layout.children) {
for (let i = 0; i < layout.children.length; i += 1) {
const child = layout.children[i];
const result = findStack(layoutId, child);
if (result !== false) {
return result;
}
}
}
return false;
}
let defaultOptions;
export const LayoutStore = {
...getters,
...setters,
setDefaultOptions(options) {
defaultOptions = options;
},
getDefaultOptions() {
return defaultOptions;
}
};
//# sourceMappingURL=LayoutStore.js.map