Skip to content

Instantly share code, notes, and snippets.

@hew
Last active Nov 30, 2020
Embed
What would you like to do?
bs-react-navigation interface types for WEB

bs-react-navigation web interface for WEB (hooks api)

type navigation('a) = {
push: 'a => unit,
pop: 'a => unit,
};
[@bs.deriving abstract]
type screenOptions = {
[@bs.optional]
title: string,
};
module type StackConfig = {
type route;
let initialRoute: route;
let getScreen:
(route, navigation(route)) => (React.element, screenOptions);
};
module Create = (Config: StackConfig) => {
[@bs.deriving abstract]
type navigatorConfig = {initialRouteName: string};
[@bs.deriving abstract]
type routeProps = {route: Config.route};
module NavigationProp = {
type t;
module State = {
type t;
[@bs.get] external getParams: t => option(routeProps) = "params";
};
[@bs.send] external push: (t, string, routeProps) => unit = "push";
[@bs.get "state"] external getState: t => State.t = "";
let getParams = t => getState(t) |> State.getParams;
};
module ScreenOptions = {
type t = {. "navigation": NavigationProp.t};
};
[@bs.deriving abstract]
type routeConfig = {
params: routeProps,
screen: ScreenOptions.t => React.element,
navigationOptions: ScreenOptions.t => screenOptions,
};
let containerDisplayName = "#";
let makeNavigationProp = (navigation: NavigationProp.t) => {
push: route =>
NavigationProp.push(
navigation,
containerDisplayName,
routeProps(~route),
),
pop: _route => (),
};
let getCurrentScreen = (navigation: NavigationProp.t) => {
/** Params can be `null` in React Navigation, but we are always declaring them */
let params = NavigationProp.getParams(navigation) |> Js.Option.getExn;
let nav = makeNavigationProp(navigation);
Config.getScreen(routeGet(params), nav);
};
module Container = {
[@react.component]
let make = (~navigation: NavigationProp.t) => {
getCurrentScreen(navigation) |> fst
};
};
let route =
routeConfig(
~params=routeProps(~route=Config.initialRoute),
~screen=
(options: ScreenOptions.t) =>
<Container navigation=options##navigation />,
~navigationOptions=
(options: ScreenOptions.t) =>
getCurrentScreen(options##navigation) |> snd,
);
/* StackNavigator route */
let routes = Js.Dict.empty();
Js.Dict.set(routes, containerDisplayName, route);
/* StackNavigator config */
let config = navigatorConfig(~initialRouteName=containerDisplayName);
/* Router */
let router = ReactNavigation.Core.stackRouter(routes, config);
/* navigator */
let navigator =
ReactNavigation.Core.createNavigator(
ReactNavigation.Stack.stackView,
router,
config,
);
/* Wrap StackNavigator with the AppContainer - temporary */
let render = ReactNavigation.Web.createBrowserApp(navigator);
};
type navigation('a) = {
navigate: 'a => unit,
goBack: 'a => unit,
};
[@bs.deriving abstract]
type screenOptions = {
[@bs.optional]
title: string,
};
module type SwitchConfig = {
type route;
let initialRoute: route;
let getScreen:
(route, navigation(route)) => (React.element, screenOptions);
};
module Create = (Config: SwitchConfig) => {
[@bs.deriving abstract]
type navigatorConfig = {initialRouteName: string};
[@bs.deriving abstract]
type routeProps = {route: Config.route};
module NavigationProp = {
type t;
module State = {
type t;
[@bs.get] external getParams: t => option(routeProps) = "params";
};
[@bs.send] external navigate: (t, string, routeProps) => unit = "navigate";
[@bs.send] external goBack: unit => unit = "goBack";
[@bs.get "state"] external getState: t => State.t = "";
let getParams = t => getState(t) |> State.getParams;
};
module ScreenOptions = {
type t = {. "navigation": NavigationProp.t};
};
[@bs.deriving abstract]
type routeConfig = {
params: routeProps,
screen: ScreenOptions.t => React.element,
navigationOptions: ScreenOptions.t => screenOptions,
};
let containerDisplayName = "#router";
let makeNavigationProp = (navigation: NavigationProp.t) => {
navigate: route =>
NavigationProp.navigate(
navigation,
containerDisplayName,
routeProps(~route),
),
goBack: _ => NavigationProp.goBack(),
};
let getCurrentScreen = (navigation: NavigationProp.t) => {
/** Params can be `null` in React Navigation, but we are always declaring them */
let params = NavigationProp.getParams(navigation) |> Js.Option.getExn;
let nav = makeNavigationProp(navigation);
Config.getScreen(routeGet(params), nav);
};
module Container = {
[@react.component]
let make = (~navigation: NavigationProp.t) => {
getCurrentScreen(navigation) |> fst;
};
};
let route =
routeConfig(
~params=routeProps(~route=Config.initialRoute),
~screen=
(options: ScreenOptions.t) =>
<Container navigation=options##navigation />,
~navigationOptions=
(options: ScreenOptions.t) =>
getCurrentScreen(options##navigation) |> snd,
);
/* SwitchNavigator route */
let routes = Js.Dict.empty();
Js.Dict.set(routes, containerDisplayName, route);
/* SwitchNavigator config */
let config = navigatorConfig(~initialRouteName=containerDisplayName);
/* Router */
let router = ReactNavigation.Core.switchRouter(routes, config);
/* navigator */
let navigator =
ReactNavigation.Core.createNavigator(
ReactNavigation.Switch.switchView,
router,
config,
);
/* Wrap SwitchNavigator with the AppContainer - temporary */
let render = ReactNavigation.Web.createBrowserApp(navigator);
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment