hyper-router 2.4.1 → 4.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (37) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +330 -268
  3. data/lib/hyper-router.rb +30 -15
  4. data/lib/hyper-router/class_methods.rb +53 -0
  5. data/lib/hyper-router/component_methods.rb +63 -0
  6. data/lib/hyper-router/history.rb +22 -0
  7. data/lib/hyper-router/location.rb +29 -0
  8. data/lib/hyper-router/match.rb +18 -0
  9. data/lib/hyper-router/react-router-source.rb +4 -2
  10. data/lib/{react/router → hyper-router}/version.rb +1 -1
  11. data/lib/hyperloop/router.rb +36 -0
  12. data/lib/hyperloop/router/base.rb +12 -0
  13. data/lib/hyperloop/router/base/class_methods.rb +21 -0
  14. data/lib/hyperloop/router/browser.rb +12 -0
  15. data/lib/hyperloop/router/browser/class_methods.rb +15 -0
  16. data/lib/hyperloop/router/component.rb +28 -0
  17. data/lib/hyperloop/router/hash.rb +12 -0
  18. data/lib/hyperloop/router/hash/class_methods.rb +15 -0
  19. data/lib/hyperloop/router/memory.rb +12 -0
  20. data/lib/hyperloop/router/memory/class_methods.rb +15 -0
  21. data/lib/hyperloop/router/static.rb +12 -0
  22. data/lib/hyperloop/router/static/class_methods.rb +15 -0
  23. data/lib/react/router.rb +2 -128
  24. data/lib/react/router/dom.rb +7 -0
  25. data/lib/react/router/history.rb +19 -25
  26. data/lib/src/history.min.js +1 -0
  27. data/lib/src/react-router-dom.min.js +2 -0
  28. data/lib/src/react-router.min.js +1 -0
  29. metadata +34 -21
  30. data/lib/promise_extras.rb +0 -7
  31. data/lib/react/router/dsl.rb +0 -31
  32. data/lib/react/router/dsl/index.rb +0 -11
  33. data/lib/react/router/dsl/route.rb +0 -89
  34. data/lib/react/router/dsl/route/hooks.rb +0 -21
  35. data/lib/react/router/dsl/route/wrappers.rb +0 -104
  36. data/lib/react/router/dsl/transition_context.rb +0 -27
  37. data/lib/src/react-router.js +0 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 3d049a9896020bcede09745f990b68f1714b09fe
4
- data.tar.gz: 894dd7c5cc038f0dea86f0e39fa05f3832ba91e3
3
+ metadata.gz: 77e89bd0516ef8221fa2520ca3959c01b3310818
4
+ data.tar.gz: 33a47f5a63a77de06ab7d13947cdc53d7997dc07
5
5
  SHA512:
6
- metadata.gz: b6fe35cae68685cbeee3b972c0379b9273aa2a93d8bd90780bb2185011e2f727f500f9eab141156889d9ba850eb118585a800de7d792317dea53bd0617934206
7
- data.tar.gz: 52b5511e0343a4279ac9d3510734f7ba2394c1f6d7748c10035ddca5fd784eb8d1d45bb6ae5ed2e184f1bc47c92647cb6c5682582fc0b3cef9ea4de9c40c66cb
6
+ metadata.gz: 8c78ae7c11bc1942b5f46ba15626cf87f879f4059a4716723d937dc463ef216c1606a845ab9c895b4215ddf22c2163cacf07336c259e4c1c4d92c2a680a6071b
7
+ data.tar.gz: 164b196fce9e58159800e1dc44ed33830c24dd24e49cc8274a1a0b1f96be6c84401da08be1ec6422f0734d5dd41b2c15902944b33b58e4aa25d8be4ccfad967e
data/README.md CHANGED
@@ -1,384 +1,446 @@
1
- # ![](https://github.com/Serzhenka/hyper-loop-logos/blob/master/hyper-router_150.png)Hyper-router
1
+ ## HyperRouter
2
2
 
3
- The Hyperloop Router allows you write and use the React Router in Ruby through Opal.
3
+ HyperRouter allows you write and use the React Router in Ruby through Opal.
4
4
 
5
5
  ## Installation
6
6
 
7
7
  Add this line to your application's Gemfile:
8
-
9
8
  ```ruby
10
9
  gem 'hyper-router'
11
10
  ```
11
+ Or execute:
12
+ ```bash
13
+ gem install hyper-router
14
+ ```
12
15
 
13
- And then execute:
14
-
15
- $ bundle
16
-
17
- ## Usage
18
-
19
- This is simply a DSL wrapper on [react-router](....)
20
-
21
- ### DSL
22
-
23
- The following DSL:
16
+ Then add this to your components.rb:
17
+ ```ruby
18
+ require 'hyper-router'
19
+ ```
24
20
 
21
+ ### Using the included source
22
+ Add this to your component.rb:
25
23
  ```ruby
26
- route("/", mounts: App, index: Home) do
27
- route("about")
28
- route("inbox") do
29
- redirect('messages/:id').to { | params | "/messages/#{params[:id]}" }
30
- end
31
- route(mounts: Inbox) do
32
- route("messages/:id")
33
- end
34
- end
24
+ require 'hyper-router/react-router-source'
25
+ require 'hyper-router'
35
26
  ```
36
27
 
37
- Is equivalent to this route configuration:
28
+ ### Using with NPM/Webpack
29
+ react-router has now been split into multiple packages, so make sure they are all installed
30
+ ```bash
31
+ npm install react-router react-router-dom history --save
32
+ ```
38
33
 
34
+ Add these to your webpack js file:
39
35
  ```javascript
40
- const routes = {
41
- path: '/',
42
- component: App,
43
- indexRoute: { component: Dashboard },
44
- childRoutes: [
45
- { path: 'about', component: About },
46
- {
47
- path: 'inbox',
48
- component: Inbox,
49
- childRoutes: [{
50
- path: 'messages/:id',
51
- onEnter: ({ params }, replace) => replace(`/messages/${params.id}`)
52
- }]
53
- },
54
- {
55
- component: Inbox,
56
- childRoutes: [{
57
- path: 'messages/:id', component: Message
58
- }]
59
- }
60
- ]
61
- }
36
+ ReactRouter = require('react-router')
37
+ ReactRouterDOM = require('react-router-dom')
38
+ History = require('history')
62
39
  ```
63
40
 
64
- The basic dsl syntax is designed with the following in mind:
41
+ ## Usage
65
42
 
66
- 1. Most routes have a path so that is the assumed first argument.
67
- 2. Use `mounts` rather than component (reads better?)
68
- 3. Convention over configuration, given a path, the component name can be derived.
69
- 4. Redirect takes the path, and a block (similar to the JSX DSL)
70
- 5. The first param to route can be skipped per the documentation
71
- 6. Use standard ruby lower case method names instead of caps (reserve those for components)
43
+ This is simply a DSL wrapper on [react-router](https://github.com/ReactTraining/react-router)
72
44
 
73
- The above example does not cover all the possible syntax, here are the other methods and options:
45
+ ## Warning!!
46
+ The folks over at react-router have gained a reputation for all their API rewrites, so with V4 we have made some changes to follow.
47
+ This version is **incompatible** with previous versions' DSL.
74
48
 
75
- #### enter / leave / change transition hooks
49
+ ### DSL
76
50
 
77
- for adding an onEnter or onLeave hook you would say:
51
+ Here is the basic example that is used on the [react-router site](https://reacttraining.com/react-router/)
78
52
 
79
- ```ruby
80
- route("foo").on(:leave) { | t | ... }.on(:enter) { | t |.... }
53
+ ```javascript
54
+ import React from 'react'
55
+ import {
56
+ BrowserRouter as Router,
57
+ Route,
58
+ Link
59
+ } from 'react-router-dom'
60
+
61
+ const BasicExample = () => (
62
+ <Router>
63
+ <div>
64
+ <ul>
65
+ <li><Link to="/">Home</Link></li>
66
+ <li><Link to="/about">About</Link></li>
67
+ <li><Link to="/topics">Topics</Link></li>
68
+ </ul>
69
+
70
+ <hr/>
71
+
72
+ <Route exact path="/" component={Home}/>
73
+ <Route path="/about" component={About}/>
74
+ <Route path="/topics" component={Topics}/>
75
+ </div>
76
+ </Router>
77
+ )
78
+
79
+ const Home = () => (
80
+ <div>
81
+ <h2>Home</h2>
82
+ </div>
83
+ )
84
+
85
+ const About = () => (
86
+ <div>
87
+ <h2>About</h2>
88
+ </div>
89
+ )
90
+
91
+ const Topics = ({ match }) => (
92
+ <div>
93
+ <h2>Topics</h2>
94
+ <ul>
95
+ <li><Link to={`${match.url}/rendering`}>Rendering with React</Link></li>
96
+ <li><Link to={`${match.url}/components`}>Components</Link></li>
97
+ <li><Link to={`${match.url}/props-v-state`}>Props v. State</Link></li>
98
+ </ul>
99
+
100
+ <Route path={`${match.url}/:topicId`} component={Topic}/>
101
+ <Route exact path={match.url} render={() => (
102
+ <h3>Please select a topic.</h3>
103
+ )}/>
104
+ </div>
105
+ )
106
+
107
+ const Topic = ({ match }) => (
108
+ <div>
109
+ <h3>{match.params.topicId}</h3>
110
+ </div>
111
+ )
112
+
113
+ export default BasicExample
81
114
  ```
82
- which follows the react.rb event handler convention.
83
-
84
- A `TransitionContext` object will be passed to the handler, which has the following methods:
85
-
86
- | method | available on | description |
87
- |-----------|------------------|-----------------|
88
- | `next_state` | `:change`, `:enter` | returns the next state object |
89
- | `prev_state` | `:change` | returns the previous state object |
90
- | `replace` | `:change`, `:enter` | pass `replace` a new path |
91
- | `promise` | `:change`, `:enter` | returns a new promise. multiple calls returns the same promise |
92
-
93
- If you return a promise from the `:change` or `:enter` hooks, the transition will wait till the promise is resolved before proceeding. For simplicity you can call the promise method, but you can also use some other method to define the promise.
94
-
95
- The hooks can also be specified as proc values to the `:on_leave`, `:on_enter`, `:on_change` options.
96
115
 
97
- #### multiple component mounting
116
+ Here is what it looks like for us:
117
+ ```ruby
118
+ class BasicExample < Hyperloop::Router
119
+ history :browser
120
+
121
+ route do
122
+ DIV do
123
+ UL do
124
+ LI { Link('/') { 'Home' } }
125
+ LI { Link('/about') { 'About' } }
126
+ LI { Link('/topics') { 'Topics' } }
127
+ end
98
128
 
99
- The `mounts` option can accept a single component, or a hash which will generate a `components` (plural) react-router prop, as in:
129
+ Route('/', exact: true, mounts: Home)
130
+ Route('/about', mounts: About)
131
+ Route('/topics', mounts: Topics)
132
+ end
133
+ end
134
+ end
100
135
 
101
- `route("groups", mounts: {main: Groups, sidebar: GroupsSidebar})` which is equivalent to:
136
+ class Home < Hyperloop::Router::Component
137
+ render(:div) do
138
+ H2 { 'Home' }
139
+ end
140
+ end
102
141
 
103
- `{path: "groups", components: {main: Groups, sidebar: GroupsSidebar}}` (json) or
142
+ class About < Hyperloop::Router::Component
143
+ render(:div) do
144
+ H2 { 'About' }
145
+ end
146
+ end
104
147
 
105
- `<Route path="groups" components={{main: Groups, sidebar: GroupsSidebar}} />` JSX
148
+ class Topics < Hyperloop::Router::Component
149
+ render(:div) do
150
+ H2 { 'Topics' }
151
+ UL() do
152
+ LI { Link("#{match.url}/rendering") { 'Rendering with React' } }
153
+ LI { Link("#{match.url}/components") { 'Components' } }
154
+ LI { Link("#{match.url}/props-v-state") { 'Props v. State' } }
155
+ end
156
+ Route("#{match.url}/:topic_id", mounts: Topic)
157
+ Route(match.url, exact: true) do
158
+ H3 { 'Please select a topic.' }
159
+ end
160
+ end
161
+ end
106
162
 
107
- #### The `mounts` option can also take a `Proc` or be specified as a block
163
+ class Topic < Hyperloop::Router::Component
164
+ render(:div) do
165
+ H3 { match.params[:topic_id] }
166
+ end
167
+ end
168
+ ```
108
169
 
109
- The proc is passed a TransitionContext (see **Hooks** above) and may either return a react component to be mounted, or return a promise. If a promise is returned the transition will wait till the promise is either resolved with a component, or rejected.
170
+ Since react-router migrated back to everything being a component,
171
+ this makes the DSL very easy to follow if you have already used react-router v4.
110
172
 
111
- `route("courses/:courseId", mounts: -> () { Course }`
173
+ ### Router
112
174
 
113
- is the same as:
175
+ This is the base Router class, it can either be inherited or included:
176
+ ```ruby
177
+ class MyRouter < Hyperloop::Router
178
+ end
114
179
 
115
- ```jsx
116
- <Route path="courses/:courseId" getComponent={(nextState, cb) => {cb(null, Course)}} />
180
+ class MyRouter < React::Component::Base
181
+ include Hyperloop::Router::Base
182
+ end
117
183
  ```
118
184
 
119
- Also instead of a proc, a block can be specified with the `mounts` method:
120
-
121
- `route("courses/:courseId").mounts { Course }`
122
-
123
- Which generates the same route as the above.
124
-
125
- More interesting would be something like this:
185
+ With the base Router class, you must specify the history you want to use.
126
186
 
187
+ This can be done either using a macro:
127
188
  ```ruby
128
- route("courses/:id").mounts do | ct |
129
- HTTP.get("validate-user-access/courses/#{ct.next_state[:id]}").then { Course }
189
+ class MyRouter < Hyperloop::Router
190
+ history :browser
130
191
  end
131
192
  ```
193
+ The macro accepts three options: `:browser`, `:hash`, or `:memory`.
132
194
 
133
- *Note that the above works because of promise chaining.*
134
-
135
- You can use the `mount` method multiple times with different arguments as an alternative to passing the the `mount` option a hash:
136
-
137
- `route("foo").mount(:baz) { Comp1 }.mount(:bar) { Comp2 }.mount(:bomb)`
138
-
139
- Note that if no block is given (as in `:bomb` above) the component name will be inferred from the argument (`Bomb` in this case.)
140
-
141
- #### The index component can be specified as a proc
142
-
143
- Same deal as mount...
144
-
145
- `route("foo", index: -> { MyIndex })`
146
-
147
- #### The index method
148
-
149
- Instead of specifying the index component as a param to the parent route, it can be specified as a child using the
150
- index method:
151
-
195
+ Or defining the `history` method:
152
196
  ```ruby
153
- route("/", mounts: About, index: Home) do
154
- index(mounts: MyIndex)
155
- route("about")
156
- route("privacy-policy")
197
+ class MyRouter < Hyperloop::Router
198
+ def history
199
+ self.class.browser_history
200
+ end
157
201
  end
158
202
  ```
159
203
 
160
- This is useful because the index method has all the features of a route except that it does not take a path or children.
204
+ ### BrowserRouter, HashRouter, MemoryRouter, StaticRouter
161
205
 
162
- #### The `redirect` options
206
+ Using one of these classes automatically takes care of the history for you,
207
+ so you don't need to specify one.
208
+ They also can be used by inheritance or inclusion:
163
209
 
164
- with static arguments:
165
-
166
- `redirect("/from/path/spec", to: "/to/path/spec", query: {q1: 123, q2: :abc})`
210
+ ```ruby
211
+ class MyRouter < Hyperloop::HashRouter
212
+ end
167
213
 
168
- the `:to` and `:query` options can be Procs which will receive the current state.
214
+ class MyRouter < React::Component::Base
215
+ include Hyperloop::Router::Hash
216
+ end
217
+ ```
169
218
 
170
- Or you can specify the `:to` an `:query` options with blocks:
219
+ ### Rendering a Router
171
220
 
172
- `redirect("/from/path/spec/:id").to { |curr_state| "/to/path/spec/#{current_state[:id]}"}.query { {q1: 12} }`
221
+ To render children/routes use the `route` macro, it is the equivalent to `render` of a component.
222
+ ```ruby
223
+ class MyRouter < Hyperloop::Router
224
+ ...
173
225
 
174
- #### The `index_redirect` method
226
+ route do
227
+ DIV do
228
+ H1 { 'Hello world!' }
229
+ end
230
+ end
231
+ end
232
+ ```
175
233
 
176
- just like `redirect` without the first arg: `index_redirect(to: ... query: ...)`
177
234
 
178
- ### The Router Component
235
+ ### Routes
179
236
 
180
- A router is defined as a subclass of `Hyperloop::Router` which is itself a `Hyperloop::Component`.
237
+ Routes are no longer defined separately, but are just components you call inside the router/components.
181
238
 
182
239
  ```ruby
183
- class Components::Router < Hyperloop::Router
184
- def routes # define your routes (there is no render method)
185
- route("/", mounts: About, index: Home) do
186
- route("about")
187
- route("inbox") do
188
- redirect('messages/:id').to { | params | "/messages/#{params[:id]}" }
189
- end
190
- route(mounts: Inbox) do
191
- route("messages/:id")
192
- end
240
+ class MyRouter < Hyperloop::Router
241
+ ...
242
+
243
+ route do
244
+ DIV do
245
+ Route('/', mounts: HelloWorld)
193
246
  end
194
- end
247
+ end
195
248
  end
196
- ```
197
- #### Mounting your Router
198
- You will mount this component the usual way (i.e. via `render_component`, `Element#render`, `react_render`, etc) or even by mounting it within a higher level application component.
199
249
 
200
- ```ruby
201
- class Components::App < Hyperloop::Component
202
- render(DIV) do
203
- Application::Nav()
204
- MAIN do
205
- Router()
206
- end
250
+ class HelloWorld < React::Component::Base
251
+ render do
252
+ H1 { 'Hello world!' }
207
253
  end
208
254
  end
209
255
  ```
210
256
 
211
- #### navigating
257
+ The `Route` method takes a url path, and these options:
258
+ - `mounts: Component` The component you want to mount when routed to
259
+ - `exact: Boolean` When true, the path must match the location exactly
260
+ - `strict: Boolean` When true, the path will only match if the location and path **both** have/don't have a trailing slash
261
+ It can also take a block instead of the `mounts` option.
212
262
 
213
- Create links to your routes with `Router::Link`
214
263
  ```ruby
215
- #Application::Nav
216
- LI.nav_link { TestRouter::Link("/") { "Home" } }
217
- LI.nav_link { TestRouter::Link("/about") { "About" } }
218
- params.messsages.each do |msg|
219
- LI.nav_link { TestRouter::Link("/inbox/messages/#{msg.id}") { msg.title } }
220
- end
221
- ```
264
+ class MyRouter < Hyperloop::Router
265
+ ...
222
266
 
223
- Additionally, you can manipulate the history with by passing JS as so
224
- ```ruby
225
- # app/views/components/app_links.rb
226
- class Components::AppLinks
227
- class << self
228
- if RUBY_ENGINE == 'opal'
229
- def inbox
230
- `window.ReactRouter.browserHistory.push('/inbox');`
231
- end
232
- def message(id)
233
- `window.ReactRouter.browserHistory.push('/messages/#{id}');`
267
+ route do
268
+ DIV do
269
+ Route('/', exact: true) do
270
+ H1 { 'Hello world!' }
234
271
  end
235
272
  end
236
273
  end
237
274
  end
238
275
  ```
239
-
240
-
241
- #### Other router hooks:
242
-
243
- There are several other methods that can be redefined to modify the routers behavior
244
-
245
- #### history
246
-
276
+ The block will give you the match, location, and history data:
247
277
  ```ruby
248
- class Router < Hyperloop::Router
249
- def history
250
- ... return a history object
278
+ class MyRouter < Hyperloop::Router
279
+ ...
280
+
281
+ route do
282
+ DIV do
283
+ Route('/:name') do |match, location, history|
284
+ H1 { "Hello #{match.params[:foo]} from #{location.pathname}, click me to go back!" }
285
+ .on(:click) { history.go_back }
286
+ end
287
+ end
251
288
  end
252
289
  end
253
290
  ```
254
291
 
255
- The two standard history objects are predefined as `browser_history` and `hash_history` so you can say:
256
-
292
+ It is recommended to inherit from `Hyperloop::Router::Component` for components mounted by routes.
293
+ This automatically sets the `match`, `location`, and `history` params,
294
+ and also gives you instance methods with those names.
295
+ You can use either `params.match` or just `match`.
296
+ and gives you access to the Route method and more.
297
+ This allows you to create inner routes as you need them.
257
298
  ```ruby
258
- ...
259
- def history
260
- browser_history
261
- end
262
- ```
263
-
264
- or just
299
+ class MyRouter < Hyperloop::Router
300
+ ...
265
301
 
266
- ```ruby
267
- ...
268
- alias_method :history :browser_history
269
- ```
270
-
271
- #### create_element
272
-
273
- `create_element` (if defined) is passed the component that the router will render, and its params. Use it to intercept, inspect and/or modify the component behavior.
274
-
275
- `create_element` can return any of these values:
302
+ route do
303
+ DIV do
304
+ Route('/:name', mounts: Greet)
305
+ end
306
+ end
307
+ end
276
308
 
277
- + Any falsy value: indicating that rendering should continue with no modification to behavior.
278
- + A `React::Element`, or a native `React.Element` which will be used for rendering.
279
- + Any truthy value: indicating that a new Element should be created using the (probably modified) params
309
+ class Greet < Hyperloop::Router::Component
310
+ render(DIV) do
311
+ H1 { "Hello #{match.params[:foo]}!" }
312
+ Route(match.url, exact: true) do
313
+ H2 { 'What would you like to do?' }
314
+ end
315
+ Route("#{match.url}/:activity", mounts: Activity)
316
+ end
317
+ end
280
318
 
281
- ```ruby
282
- class Router < Hyperloop::Router
283
- def create_element(component, component_params)
284
- # add the param :time_stamp to each element as its rendered
285
- React.create_element(component, component_params.merge(time_stamp: Time.now))
319
+ class Activity < Hyperloop::Router::Component
320
+ render(DIV) do
321
+ H2 { params.match.params[:activity] }
286
322
  end
287
323
  end
288
324
  ```
289
325
 
290
- The above could be simplified to:
326
+ Routes will **always** render alongside sibling routes that match as well.
291
327
 
292
328
  ```ruby
293
- ...
294
- def create_element(component, component_params)
295
- component_params[:time_stamp] = Time.now
329
+ class MyRouter < Hyperloop::Router
330
+ ...
331
+
332
+ route do
333
+ DIV do
334
+ Route('/goodbye', mounts: Goodbye)
335
+ Route('/:name', mounts: Greet)
336
+ end
296
337
  end
338
+ end
297
339
  ```
298
340
 
299
- Just make sure that you return a truthy value otherwise it will ignore any changes to component or params.
341
+ ### Switch
300
342
 
301
- Or if you just wanted some kind of logging:
343
+ Going to `/goodbye` would match `/:name` as well and render `Greet` with the `name` param with the value 'goodbye'.
344
+ To avoid this behavior and only render one matching route at a time, use a `Switch` component.
302
345
 
303
346
  ```ruby
304
- ...
305
- def create_element(component, component_params)
306
- puts "[#{Time.now}] Rendering: #{component.name}" # puts returns nil, so we are jake mate
347
+ class MyRouter < Hyperloop::Router
348
+ ...
349
+
350
+ route do
351
+ DIV do
352
+ Switch do
353
+ Route('/goodbye', mounts: Goodbye)
354
+ Route('/:name', mounts: Greet)
355
+ end
356
+ end
307
357
  end
358
+ end
308
359
  ```
309
360
 
310
- The component_params will always contain the following keys as native js objects, and they must stay native js objects:
361
+ Now, going to `/goodbye` would match the `Goodbye` route first and only render that component.
311
362
 
312
- + `children`
313
- + `history`
314
- + `location`
315
- + `params`
316
- + `route`
317
- + `route_params`
318
- + `routes`
363
+ ### Links
319
364
 
320
- We will try to get more fancy with a later version of reactrb-router ;-)
365
+ Links are available to Routers, classes that inherit from `HyperLoop::Router::Component`,
366
+ or by including `Hyperloop::Router::ComponentMethods`.
321
367
 
322
- #### `stringify_query(params_hash)` <- needs work
368
+ The `Link` method takes a url path, and these options:
369
+ - `search: String` adds the specified string to the search query
370
+ - `hash: String` adds the specified string to the hash location
371
+ It can also take a block of children to render inside it.
372
+ ```ruby
373
+ class MyRouter < Hyperloop::Router
374
+ ...
323
375
 
324
- The method used to convert an object from <Link>s or calls to transitionTo to a URL query string.
376
+ route do
377
+ DIV do
378
+ Link('/Gregor Clegane')
325
379
 
326
- ```ruby
327
- class Router < Hyperloop::Router
328
- def stringify_query(params_hash)
329
- # who knows doc is a little unclear on this one...is it being passed the full params_hash or just
330
- # the query portion.... we shall see...
380
+ Route('/', exact: true) { H1() }
381
+ Route('/:name') do |match|
382
+ H1 { "Will #{match.params[:name]} eat all the chickens?" }
383
+ end
384
+ end
331
385
  end
332
386
  end
333
387
  ```
334
388
 
335
- #### `parse_query_string(string)` <- needs work
336
-
337
- The method used to convert a query string into the route components's param hash
338
-
339
- #### `on_error(data)`
340
-
341
- While the router is matching, errors may bubble up, here is your opportunity to catch and deal with them. Typically these will come when promises are rejected (see the DSL above for returning promises to handle async behaviors.)
342
-
343
- #### `on_update`
344
-
345
- Called whenever the router updates its state in response to URL changes.
346
-
347
- #### `render`
348
-
349
- A `Router` default `render` looks like this:
389
+ ### NavLinks
350
390
 
391
+ NavLinks are the same as Links, but will add styling attributes when it matches the current url
392
+ - `active_class: String` adds the class to the link when the url matches
393
+ - `active_style: String` adds the style to the link when the url matches
394
+ - `active: Proc` A proc that will add extra logic to determine if the link is active
351
395
  ```ruby
352
- def render
353
- # Router.router renders the native router component
354
- Router.router(build_params)
396
+ class MyRouter < Hyperloop::Router
397
+ ...
398
+
399
+ route do
400
+ DIV do
401
+ NavLink('/Gregor Clegane', active_class: 'active-link')
402
+ NavLink('/Rodrik Cassel', active_style: { color: 'grey' })
403
+ NavLink('/Oberyn Martell',
404
+ active: ->(match, location) {
405
+ match && match.params[:name] && match.params[:name] =~ /Martell/
406
+ })
407
+
408
+ Route('/', exact: true) { H1() }
409
+ Route('/:name') do |match|
410
+ H1 { "Will #{match.params[:name]} eat all the chickens?" }
411
+ end
412
+ end
355
413
  end
414
+ end
356
415
  ```
357
416
 
417
+ ### Pre-rendering
358
418
 
359
- This is primarily for integrating with other libraries that need to participate in rendering before the route components are rendered. It defaults to render={(props) => <RouterContext {...props} />}.
360
-
361
- Ensure that you render a <RouterContext> at the end of the line, passing all the props passed to render.
362
-
363
- ### Hyperloop::Router::Component
364
-
365
- The class Hyperloop::Router::Component is a subclass of Hyperloop::Component that predefines the params that the router will be passing in to your component. This includes
366
-
367
- `params.location`
368
-
369
- The current location.
370
-
371
- `params.params`
419
+ Pre-rendering has been made extremely simple in this new version.
420
+ Under the hood a StaticRouter is used whenever a Router component is prerendering.
421
+ To prerender correctly though you will need to give it the current path.
422
+ Since there is no DOM, you must pass in the current path from your controller/view as a param.
423
+ There is a special param macro called `prerender_path`,
424
+ which still acts as a normal param but will use that param as the current path in prerendering.
372
425
 
373
- The dynamic segments of the URL.
374
-
375
- `params.route`
426
+ ```ruby
427
+ class MyController < ApplicationController
428
+ def show
429
+ render component: 'MyRouter', props: { current_path: request.path }
430
+ end
431
+ end
376
432
 
377
- The route that rendered this component.
433
+ class MyRouter < Hyperloop::Router
434
+ prerender_path :current_path
378
435
 
379
- `params.route_params`
436
+ route do
437
+ DIV do
438
+ Route('/:name', mounts: Greet)
439
+ end
440
+ end
441
+ end
442
+ ```
380
443
 
381
- The subset of `params.params` that were directly specified in this component's route. For example, if the route's path is `users/:user_id` and the URL is /users/123/portfolios/345 then `params.route_params` will be `{user_id: '123'}`, and `params.params` will be `{user_id: '123', portfolio_id: 345}`.
382
444
 
383
445
  ## Development
384
446