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.
- checksums.yaml +4 -4
- data/README.md +330 -268
- data/lib/hyper-router.rb +30 -15
- data/lib/hyper-router/class_methods.rb +53 -0
- data/lib/hyper-router/component_methods.rb +63 -0
- data/lib/hyper-router/history.rb +22 -0
- data/lib/hyper-router/location.rb +29 -0
- data/lib/hyper-router/match.rb +18 -0
- data/lib/hyper-router/react-router-source.rb +4 -2
- data/lib/{react/router → hyper-router}/version.rb +1 -1
- data/lib/hyperloop/router.rb +36 -0
- data/lib/hyperloop/router/base.rb +12 -0
- data/lib/hyperloop/router/base/class_methods.rb +21 -0
- data/lib/hyperloop/router/browser.rb +12 -0
- data/lib/hyperloop/router/browser/class_methods.rb +15 -0
- data/lib/hyperloop/router/component.rb +28 -0
- data/lib/hyperloop/router/hash.rb +12 -0
- data/lib/hyperloop/router/hash/class_methods.rb +15 -0
- data/lib/hyperloop/router/memory.rb +12 -0
- data/lib/hyperloop/router/memory/class_methods.rb +15 -0
- data/lib/hyperloop/router/static.rb +12 -0
- data/lib/hyperloop/router/static/class_methods.rb +15 -0
- data/lib/react/router.rb +2 -128
- data/lib/react/router/dom.rb +7 -0
- data/lib/react/router/history.rb +19 -25
- data/lib/src/history.min.js +1 -0
- data/lib/src/react-router-dom.min.js +2 -0
- data/lib/src/react-router.min.js +1 -0
- metadata +34 -21
- data/lib/promise_extras.rb +0 -7
- data/lib/react/router/dsl.rb +0 -31
- data/lib/react/router/dsl/index.rb +0 -11
- data/lib/react/router/dsl/route.rb +0 -89
- data/lib/react/router/dsl/route/hooks.rb +0 -21
- data/lib/react/router/dsl/route/wrappers.rb +0 -104
- data/lib/react/router/dsl/transition_context.rb +0 -27
- data/lib/src/react-router.js +0 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 77e89bd0516ef8221fa2520ca3959c01b3310818
|
4
|
+
data.tar.gz: 33a47f5a63a77de06ab7d13947cdc53d7997dc07
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8c78ae7c11bc1942b5f46ba15626cf87f879f4059a4716723d937dc463ef216c1606a845ab9c895b4215ddf22c2163cacf07336c259e4c1c4d92c2a680a6071b
|
7
|
+
data.tar.gz: 164b196fce9e58159800e1dc44ed33830c24dd24e49cc8274a1a0b1f96be6c84401da08be1ec6422f0734d5dd41b2c15902944b33b58e4aa25d8be4ccfad967e
|
data/README.md
CHANGED
@@ -1,384 +1,446 @@
|
|
1
|
-
|
1
|
+
## HyperRouter
|
2
2
|
|
3
|
-
|
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
|
-
|
14
|
-
|
15
|
-
|
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
|
-
|
27
|
-
|
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
|
-
|
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
|
-
|
41
|
-
|
42
|
-
|
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
|
-
|
41
|
+
## Usage
|
65
42
|
|
66
|
-
|
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
|
-
|
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
|
-
|
49
|
+
### DSL
|
76
50
|
|
77
|
-
|
51
|
+
Here is the basic example that is used on the [react-router site](https://reacttraining.com/react-router/)
|
78
52
|
|
79
|
-
```
|
80
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
136
|
+
class Home < Hyperloop::Router::Component
|
137
|
+
render(:div) do
|
138
|
+
H2 { 'Home' }
|
139
|
+
end
|
140
|
+
end
|
102
141
|
|
103
|
-
|
142
|
+
class About < Hyperloop::Router::Component
|
143
|
+
render(:div) do
|
144
|
+
H2 { 'About' }
|
145
|
+
end
|
146
|
+
end
|
104
147
|
|
105
|
-
|
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
|
-
|
163
|
+
class Topic < Hyperloop::Router::Component
|
164
|
+
render(:div) do
|
165
|
+
H3 { match.params[:topic_id] }
|
166
|
+
end
|
167
|
+
end
|
168
|
+
```
|
108
169
|
|
109
|
-
|
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
|
-
|
173
|
+
### Router
|
112
174
|
|
113
|
-
is the
|
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
|
-
|
116
|
-
|
180
|
+
class MyRouter < React::Component::Base
|
181
|
+
include Hyperloop::Router::Base
|
182
|
+
end
|
117
183
|
```
|
118
184
|
|
119
|
-
|
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
|
-
|
129
|
-
|
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
|
-
|
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
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
197
|
+
class MyRouter < Hyperloop::Router
|
198
|
+
def history
|
199
|
+
self.class.browser_history
|
200
|
+
end
|
157
201
|
end
|
158
202
|
```
|
159
203
|
|
160
|
-
|
204
|
+
### BrowserRouter, HashRouter, MemoryRouter, StaticRouter
|
161
205
|
|
162
|
-
|
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
|
-
|
165
|
-
|
166
|
-
|
210
|
+
```ruby
|
211
|
+
class MyRouter < Hyperloop::HashRouter
|
212
|
+
end
|
167
213
|
|
168
|
-
|
214
|
+
class MyRouter < React::Component::Base
|
215
|
+
include Hyperloop::Router::Hash
|
216
|
+
end
|
217
|
+
```
|
169
218
|
|
170
|
-
|
219
|
+
### Rendering a Router
|
171
220
|
|
172
|
-
|
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
|
-
|
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
|
-
###
|
235
|
+
### Routes
|
179
236
|
|
180
|
-
|
237
|
+
Routes are no longer defined separately, but are just components you call inside the router/components.
|
181
238
|
|
182
239
|
```ruby
|
183
|
-
class
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
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
|
-
|
201
|
-
|
202
|
-
|
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
|
-
|
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
|
-
|
216
|
-
|
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
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
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
|
249
|
-
|
250
|
-
|
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
|
-
|
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
|
-
|
260
|
-
browser_history
|
261
|
-
end
|
262
|
-
```
|
263
|
-
|
264
|
-
or just
|
299
|
+
class MyRouter < Hyperloop::Router
|
300
|
+
...
|
265
301
|
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
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
|
-
|
278
|
-
|
279
|
-
|
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
|
-
|
282
|
-
|
283
|
-
|
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
|
-
|
326
|
+
Routes will **always** render alongside sibling routes that match as well.
|
291
327
|
|
292
328
|
```ruby
|
293
|
-
|
294
|
-
|
295
|
-
|
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
|
-
|
341
|
+
### Switch
|
300
342
|
|
301
|
-
|
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
|
-
|
306
|
-
|
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
|
-
|
361
|
+
Now, going to `/goodbye` would match the `Goodbye` route first and only render that component.
|
311
362
|
|
312
|
-
|
313
|
-
+ `history`
|
314
|
-
+ `location`
|
315
|
-
+ `params`
|
316
|
-
+ `route`
|
317
|
-
+ `route_params`
|
318
|
-
+ `routes`
|
363
|
+
### Links
|
319
364
|
|
320
|
-
|
365
|
+
Links are available to Routers, classes that inherit from `HyperLoop::Router::Component`,
|
366
|
+
or by including `Hyperloop::Router::ComponentMethods`.
|
321
367
|
|
322
|
-
|
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
|
-
|
376
|
+
route do
|
377
|
+
DIV do
|
378
|
+
Link('/Gregor Clegane')
|
325
379
|
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
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
|
-
|
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
|
-
|
353
|
-
|
354
|
-
|
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
|
-
|
360
|
-
|
361
|
-
|
362
|
-
|
363
|
-
|
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
|
-
|
374
|
-
|
375
|
-
|
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
|
-
|
433
|
+
class MyRouter < Hyperloop::Router
|
434
|
+
prerender_path :current_path
|
378
435
|
|
379
|
-
|
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
|
|