├── .gitignore
├── LICENSE
├── README.md
├── bsconfig.json
├── examples
├── .gitignore
├── README.md
├── bsconfig.json
├── package.json
├── public
│ ├── favicon.ico
│ ├── index.html
│ └── manifest.json
├── src
│ ├── Admin.re
│ ├── App.re
│ ├── Home.re
│ ├── NotFound.re
│ ├── index.css
│ └── index.re
└── yarn.lock
├── package.json
├── src
└── ReRoute.re
└── yarn.lock
/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | *.log
3 | npm-debug.log*
4 | yarn-debug.log*
5 | yarn-error.log*
6 | package-lock.json
7 |
8 | # Dependency directories
9 | node_modules/
10 |
11 | # Optional npm cache directory
12 | .npm
13 |
14 | # Optional eslint cache
15 | .eslintcache
16 |
17 | # Yarn Integrity file
18 | .yarn-integrity
19 |
20 | .merlin
21 |
22 | lib
23 | *.bs.js
24 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2018 Callstack
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # reroute
2 |
3 | > a fast, declarative microrouter for reason-react
4 |
5 | ## Getting started
6 |
7 | ### Installation
8 |
9 | Open a Terminal in your project's folder and run,
10 |
11 | ```
12 | $ yarn add reason-reroute
13 | ```
14 |
15 | After installation, you will need to add this library to your `bsconfig.json` dependencies
16 |
17 | ```
18 | "bs-dependencies": [
19 | "reason-react",
20 | "reason-reroute"
21 | ],
22 | ```
23 |
24 | ## Usage
25 |
26 | ```reason
27 | module RouterConfig = {
28 | type route =
29 | | Admin
30 | | Home;
31 | let routeFromUrl = (url: ReasonReact.Router.url) =>
32 | switch url.path {
33 | | ["admin"] => Admin
34 | | [] => Home
35 | };
36 | let routeToUrl = (route: route) =>
37 | switch route {
38 | | Admin => "/admin"
39 | | Home => "/"
40 | };
41 | };
42 |
43 | module Router = ReRoute.CreateRouter(RouterConfig);
44 |
45 | let component = ReasonReact.statelessComponent("App");
46 |
47 | let make = _children => {
48 | ...component,
49 | render: _self =>
50 |
51 | ...(
52 | (~currentRoute) =>
53 | switch currentRoute {
54 | | RouterConfig.Admin =>
55 | | RouterConfig.Home =>
56 | }
57 | )
58 |
59 | };
60 | ```
61 |
62 | ## API
63 |
64 | Sections below are under construction.
65 |
66 | ### Link
67 |
68 | ### Container
69 |
70 | ## Rationale
71 |
72 | ReasonReact comes with a router ([`ReasonReact.Router`](https://reasonml.github.io/reason-react/docs/en/router.html)) by default. It offers minimal yet powerful API that is suitable for applications at any scale. However, being just an API, it leaves the routing logic up to the developer. This library builds on top of it to provide an elegant interface for working with routes that is ready to use, predictable and consistent across apps you create.
73 |
74 | ## Credits
75 |
76 | The concept of `reroute` has been highly influenced by [@thangngoc89](https://github.com/thangngoc89) and his [reference implementation](https://gist.github.com/thangngoc89/c9162c0263df5427fe9a36fc7f94ac94). Thank you for pushing this forward!
77 |
78 | ## License
79 |
80 | MIT (c) 2018 Callstack
81 |
--------------------------------------------------------------------------------
/bsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "reason-reroute",
3 | "bsc-flags": ["-bs-no-version-header", "-bs-super-errors"],
4 | "refmt": 3,
5 | "bs-dependencies": ["reason-react"],
6 | "reason": {
7 | "react-jsx": 2
8 | },
9 | "namespace": false,
10 | "sources": [
11 | {
12 | "dir": "src",
13 | "public": "all"
14 | }
15 | ]
16 | }
17 |
--------------------------------------------------------------------------------
/examples/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/ignore-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 |
6 | # testing
7 | /coverage
8 |
9 | # production
10 | /build
11 |
12 | # bucklescript
13 | /lib
14 | /types
15 | .merlin
16 |
17 | # misc
18 | .DS_Store
19 | .env.local
20 | .env.development.local
21 | .env.test.local
22 | .env.production.local
23 |
24 | npm-debug.log*
25 | yarn-debug.log*
26 | yarn-error.log*
27 |
--------------------------------------------------------------------------------
/examples/README.md:
--------------------------------------------------------------------------------
1 | # Reroute example
2 |
3 | ### Get started
4 |
5 | 1. Install dependencies: `yarn` or `npm install`
6 | 2. Run the example app: `yarn start`
7 |
--------------------------------------------------------------------------------
/examples/bsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "reason-scripts",
3 | "sources": ["src"],
4 | "bs-dependencies": ["reason-react", "bs-jest", "reason-reroute"],
5 | "reason": {
6 | "react-jsx": 2
7 | },
8 | "bsc-flags": ["-bs-super-errors"],
9 | "refmt": 3
10 | }
11 |
--------------------------------------------------------------------------------
/examples/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "examples",
3 | "version": "0.1.0",
4 | "private": true,
5 | "dependencies": {
6 | "react": "^16.2.0",
7 | "react-dom": "^16.2.0",
8 | "reason-reroute": "../",
9 | "reason-scripts": "0.8.0"
10 | },
11 | "scripts": {
12 | "start": "react-scripts start",
13 | "build": "react-scripts build",
14 | "test": "react-scripts test --env=jsdom",
15 | "eject": "react-scripts eject",
16 | "prepare": "npm link bs-platform"
17 | },
18 | "devDependencies": {
19 | "bs-jest": "^0.3.2",
20 | "reason-react": "^0.3.2"
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/examples/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/callstackincubator/reroute/2af42d862edd9a7e84bd44bf357fc83e01bdf2bc/examples/public/favicon.ico
--------------------------------------------------------------------------------
/examples/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
11 |
12 |
13 |
22 | React App
23 |
24 |
25 |
28 |
29 |
39 |
40 |
41 |
--------------------------------------------------------------------------------
/examples/public/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "short_name": "React App",
3 | "name": "Create React App Sample",
4 | "icons": [
5 | {
6 | "src": "favicon.ico",
7 | "sizes": "64x64 32x32 24x24 16x16",
8 | "type": "image/x-icon"
9 | }
10 | ],
11 | "start_url": "./index.html",
12 | "display": "standalone",
13 | "theme_color": "#000000",
14 | "background_color": "#ffffff"
15 | }
16 |
--------------------------------------------------------------------------------
/examples/src/Admin.re:
--------------------------------------------------------------------------------
1 | let component = ReasonReact.statelessComponent("Admin");
2 |
3 | let make = _children => {
4 | ...component,
5 | render: _self =>
6 |
7 |
(ReasonReact.stringToElement("Admin"))
8 |
(ReasonReact.stringToElement("This is an admin page"))
9 |
10 | };
--------------------------------------------------------------------------------
/examples/src/App.re:
--------------------------------------------------------------------------------
1 | module RouterConfig = {
2 | type route =
3 | | Admin
4 | | Home
5 | | NotFound;
6 | let routeFromUrl = (url: ReasonReact.Router.url) =>
7 | switch url.path {
8 | | ["admin"] => Admin
9 | | [] => Home
10 | | _ => NotFound
11 | };
12 | let routeToUrl = (route: route) =>
13 | switch route {
14 | | Admin => "/admin"
15 | | Home => "/"
16 | | NotFound => ""
17 | };
18 | };
19 |
20 | module Router = ReRoute.CreateRouter(RouterConfig);
21 |
22 | let component = ReasonReact.statelessComponent("App");
23 |
24 | let make = _children => {
25 | ...component,
26 | render: _self =>
27 |
28 | ...(
29 | (~currentRoute) =>
30 |
31 |
32 | (ReasonReact.stringToElement("Menu"))
33 |
34 | - (ReasonReact.stringToElement("Home"))
35 |
36 |
37 | - (ReasonReact.stringToElement("Admin"))
38 |
39 |
40 | (
41 | switch currentRoute {
42 | | RouterConfig.Admin =>
43 | | RouterConfig.Home =>
44 | | RouterConfig.NotFound =>
45 | }
46 | )
47 |
48 | )
49 |
50 | };
--------------------------------------------------------------------------------
/examples/src/Home.re:
--------------------------------------------------------------------------------
1 | let component = ReasonReact.statelessComponent("Home");
2 |
3 | let make = _children => {
4 | ...component,
5 | render: _self =>
6 |
7 |
(ReasonReact.stringToElement("Home"))
8 |
(ReasonReact.stringToElement("Welcome to the home page!"))
9 |
10 | };
--------------------------------------------------------------------------------
/examples/src/NotFound.re:
--------------------------------------------------------------------------------
1 | let component = ReasonReact.statelessComponent("NotFound");
2 |
3 | let make = _children => {
4 | ...component,
5 | render: _self =>
6 |
7 |
(ReasonReact.stringToElement("We are sorry..."))
8 |
9 | (
10 | ReasonReact.stringToElement(
11 | "Unfortunately we could not find the page you were looking for."
12 | )
13 | )
14 |
15 |
16 | (
17 | ReasonReact.stringToElement(
18 | "Use the above menu to navigate to other pages :)"
19 | )
20 | )
21 |
22 |
23 | };
--------------------------------------------------------------------------------
/examples/src/index.css:
--------------------------------------------------------------------------------
1 | body {
2 | margin: 0;
3 | padding: 0;
4 | font-family: sans-serif;
5 | }
6 |
--------------------------------------------------------------------------------
/examples/src/index.re:
--------------------------------------------------------------------------------
1 | [%bs.raw {|require('./index.css')|}];
2 |
3 | ReactDOMRe.renderToElementWithId(, "root");
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "reason-reroute",
3 | "version": "0.0.4",
4 | "description": "Tiny wrapper around ReasonReact.Router ",
5 | "main": "index.js",
6 | "scripts": {
7 | "build": "bsb -make-world",
8 | "start": "bsb -make-world -w",
9 | "clean": "bsb -clean-world",
10 | "prepublish": "npm run build",
11 | "test": "exit 0"
12 | },
13 | "keywords": [
14 | "router",
15 | "react",
16 | "reason",
17 | "reasonml"
18 | ],
19 | "repository": {
20 | "type": "git",
21 | "url": "git+https://github.com/callstack/reroute.git"
22 | },
23 | "author": "Mike Grabowski ",
24 | "license": "MIT",
25 | "bugs": {
26 | "url": "https://github.com/callstack/reroute/issues"
27 | },
28 | "homepage": "https://github.com/callstack/reroute#readme",
29 | "devDependencies": {
30 | "bs-platform": "^4.0.3",
31 | "reason-react": "^0.5.3"
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/src/ReRoute.re:
--------------------------------------------------------------------------------
1 | module type RouterConfig = {
2 | type route;
3 | let routeFromUrl: ReasonReact.Router.url => route;
4 | let routeToUrl: route => string;
5 | };
6 |
7 | module CreateRouter = (Config: RouterConfig) => {
8 | module Container = {
9 | type action =
10 | | ChangeRoute(Config.route);
11 | type state = Config.route;
12 | let component = ReasonReact.reducerComponent("CallstackRerouteRouter");
13 | let make = children => {
14 | ...component,
15 | initialState: () =>
16 | ReasonReact.Router.dangerouslyGetInitialUrl() |> Config.routeFromUrl,
17 | reducer: (action, _state) =>
18 | switch (action) {
19 | | ChangeRoute(route) => ReasonReact.Update(route)
20 | },
21 | didMount: self => {
22 | let watcherID =
23 | ReasonReact.Router.watchUrl(url =>
24 | self.send(ChangeRoute(url |> Config.routeFromUrl))
25 | );
26 | self.onUnmount(() => ReasonReact.Router.unwatchUrl(watcherID));
27 | },
28 | render: self => children(~currentRoute=self.state),
29 | };
30 | };
31 | module Link = {
32 | let component = ReasonReact.statelessComponent("CallstackRerouteLink");
33 | let make = (~route, children) => {
34 | ...component,
35 | render: _self => {
36 | let href = Config.routeToUrl(route);
37 | {
41 | event->ReactEvent.Synthetic.preventDefault;
42 | ReasonReact.Router.push(href);
43 | }
44 | )>
45 | (ReasonReact.array(children))
46 | ;
47 | },
48 | };
49 | };
50 | };
--------------------------------------------------------------------------------
/yarn.lock:
--------------------------------------------------------------------------------
1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
2 | # yarn lockfile v1
3 |
4 |
5 | asap@~2.0.3:
6 | version "2.0.6"
7 | resolved "https://registry.yarnpkg.com/asap/-/asap-2.0.6.tgz#e50347611d7e690943208bbdafebcbc2fb866d46"
8 |
9 | bs-platform@^4.0.3:
10 | version "4.0.3"
11 | resolved "https://registry.yarnpkg.com/bs-platform/-/bs-platform-4.0.3.tgz#4510c1c915cc5b169b5717e5c0ada52d3f99ff98"
12 |
13 | core-js@^1.0.0:
14 | version "1.2.7"
15 | resolved "https://registry.yarnpkg.com/core-js/-/core-js-1.2.7.tgz#652294c14651db28fa93bd2d5ff2983a4f08c636"
16 |
17 | encoding@^0.1.11:
18 | version "0.1.12"
19 | resolved "https://registry.yarnpkg.com/encoding/-/encoding-0.1.12.tgz#538b66f3ee62cd1ab51ec323829d1f9480c74beb"
20 | dependencies:
21 | iconv-lite "~0.4.13"
22 |
23 | fbjs@^0.8.16:
24 | version "0.8.16"
25 | resolved "https://registry.yarnpkg.com/fbjs/-/fbjs-0.8.16.tgz#5e67432f550dc41b572bf55847b8aca64e5337db"
26 | dependencies:
27 | core-js "^1.0.0"
28 | isomorphic-fetch "^2.1.1"
29 | loose-envify "^1.0.0"
30 | object-assign "^4.1.0"
31 | promise "^7.1.1"
32 | setimmediate "^1.0.5"
33 | ua-parser-js "^0.7.9"
34 |
35 | iconv-lite@~0.4.13:
36 | version "0.4.23"
37 | resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.23.tgz#297871f63be507adcfbfca715d0cd0eed84e9a63"
38 | dependencies:
39 | safer-buffer ">= 2.1.2 < 3"
40 |
41 | is-stream@^1.0.1:
42 | version "1.1.0"
43 | resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44"
44 |
45 | isomorphic-fetch@^2.1.1:
46 | version "2.2.1"
47 | resolved "https://registry.yarnpkg.com/isomorphic-fetch/-/isomorphic-fetch-2.2.1.tgz#611ae1acf14f5e81f729507472819fe9733558a9"
48 | dependencies:
49 | node-fetch "^1.0.1"
50 | whatwg-fetch ">=0.10.0"
51 |
52 | js-tokens@^3.0.0:
53 | version "3.0.2"
54 | resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-3.0.2.tgz#9866df395102130e38f7f996bceb65443209c25b"
55 |
56 | loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.3.1:
57 | version "1.3.1"
58 | resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.3.1.tgz#d1a8ad33fa9ce0e713d65fdd0ac8b748d478c848"
59 | dependencies:
60 | js-tokens "^3.0.0"
61 |
62 | node-fetch@^1.0.1:
63 | version "1.7.3"
64 | resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-1.7.3.tgz#980f6f72d85211a5347c6b2bc18c5b84c3eb47ef"
65 | dependencies:
66 | encoding "^0.1.11"
67 | is-stream "^1.0.1"
68 |
69 | object-assign@^4.1.0, object-assign@^4.1.1:
70 | version "4.1.1"
71 | resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
72 |
73 | promise@^7.1.1:
74 | version "7.3.1"
75 | resolved "https://registry.yarnpkg.com/promise/-/promise-7.3.1.tgz#064b72602b18f90f29192b8b1bc418ffd1ebd3bf"
76 | dependencies:
77 | asap "~2.0.3"
78 |
79 | prop-types@^15.6.0:
80 | version "15.6.1"
81 | resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.6.1.tgz#36644453564255ddda391191fb3a125cbdf654ca"
82 | dependencies:
83 | fbjs "^0.8.16"
84 | loose-envify "^1.3.1"
85 | object-assign "^4.1.1"
86 |
87 | "react-dom@>=15.0.0 || >=16.0.0":
88 | version "16.3.2"
89 | resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-16.3.2.tgz#cb90f107e09536d683d84ed5d4888e9640e0e4df"
90 | dependencies:
91 | fbjs "^0.8.16"
92 | loose-envify "^1.1.0"
93 | object-assign "^4.1.1"
94 | prop-types "^15.6.0"
95 |
96 | "react@>=15.0.0 || >=16.0.0":
97 | version "16.3.2"
98 | resolved "https://registry.yarnpkg.com/react/-/react-16.3.2.tgz#fdc8420398533a1e58872f59091b272ce2f91ea9"
99 | dependencies:
100 | fbjs "^0.8.16"
101 | loose-envify "^1.1.0"
102 | object-assign "^4.1.1"
103 | prop-types "^15.6.0"
104 |
105 | reason-react@^0.5.3:
106 | version "0.5.3"
107 | resolved "https://registry.yarnpkg.com/reason-react/-/reason-react-0.5.3.tgz#10601809742fd991109ec9d69ad4baf2c3f17540"
108 | dependencies:
109 | react ">=15.0.0 || >=16.0.0"
110 | react-dom ">=15.0.0 || >=16.0.0"
111 |
112 | "safer-buffer@>= 2.1.2 < 3":
113 | version "2.1.2"
114 | resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a"
115 |
116 | setimmediate@^1.0.5:
117 | version "1.0.5"
118 | resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285"
119 |
120 | ua-parser-js@^0.7.9:
121 | version "0.7.18"
122 | resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-0.7.18.tgz#a7bfd92f56edfb117083b69e31d2aa8882d4b1ed"
123 |
124 | whatwg-fetch@>=0.10.0:
125 | version "2.0.4"
126 | resolved "https://registry.yarnpkg.com/whatwg-fetch/-/whatwg-fetch-2.0.4.tgz#dde6a5df315f9d39991aa17621853d720b85566f"
127 |
--------------------------------------------------------------------------------