@motorcycle/router
Version:
Standard Router Driver for Motorcycle.js
165 lines (128 loc) • 4.47 kB
Markdown
# @motorcycle/router
> Standard Router Driver for Motorcycle.js
A driver built on top of [@motorcycle/history](https://github.com/motorcyclejs/history)
and [switch-path](https://github.com/staltz/switch-path) to ease the pain of routing.
Works server-side and in browsers!
## Let me have it!
```sh
npm install --save @motorcycle/router
```
## Basic Usage
```typescript
import { run } from '@motorcycle/run';
import { makeDomComponent, div, h1 } from '@motorcycle/dom';
import { History } from '@motorcycle/history';
import { Router } from '@motorcycle/router';
import { of } from 'most';
function Main(sources) {
const match$ = sources.router.define({
'/': HomeComponent,
'/other': OtherComponent
});
const page$ = match$.map(({path, value}) => {
return value({...sources, router: sources.router.path(path)});
});
return {
dom: page$.map(c => c.dom).switch(),
router: page$.map(c => c.route$).switch().startWith('/'),
};
}
const Dom = makeDomComponent(document.querySelector('#app')));
function Effects(sinks) {
const { dom } = Dom(sinks);
const { router } = Router(History(sinks));
}
run(main, Effects)
function HomeComponent() {
const route$ = ... // left as a user exercise
return {
dom: of(div([h1('home')])),
route$,
}
}
function OtherComponent() {
const route$ = ... // left as a user exercise
return {
dom: of(div([h1('other')])),
route$
}
}
```
## API
For all types not defined here, please refer to `@motorcycle/history`'s type
documentation [here](https://github.com/motorcyclejs/history#types)
#### `Router(sinks: HistorySources): RouterSources`
This is the main API of this driver. This function simply wraps `@motorcycle/history`
and returns a source object containing methods instead of a stream.
#### `RouterComponent: RouterHOC`
A convenience function, to more declaratively define your routes to
*Components*. It returns a stream of your currently matched Component.
When using the router driver directly there is more flexibility. With
the Router function, you must use routes to match to Components.
```typescript
function main(sources: Sources): Sinks {
const sinks$: Stream<Sinks> =
Router({
'/': HomeComponent, // HomeComponent :: (sources: Sources) => Sinks;
'/profile: {
'/': ProfileComponent,
'/:id': (id: number) => (sources: Sources) => ProfileId({...sources, id}),
}
}, sources);
return {
DOM: sinks$.map(sinks => sinks.dom).switch(),
router: sinks$.map(sinks => sinks.route$).switch()
};
}
```
## Types
#### `RouterSource`
This is a type representation of the object passed into your main function.
```typescript
export interface RouterSource {
history(): Stream<Location>;
path(pathname: Pathname): RouterSource;
define(routes: RouteDefinitions): Stream<DefineReturn>;
createHref(path: Pathname): Pathname;
}
```
`history(): Stream<Location>` - This method allows you to reach the underlying
stream provided by `@motorcycle/history`.
`path(pathname: Pathname): RouterSource` - This method allows you to created
nested router instances, very much like `DOM.select()` creates a new place in the
DOM tree to look for elements and events, this allows dynamically created routes
that can be matched that are decoupled from any parent routes.
`define(routes: RouteDefinitions): Stream<DefineReturn>` - This method takes
an object (anything supported by switch-path) of keys that represent your routes
and returns a stream with an object that repesents any matches.
`createHref(path: Pathname): Pathname` - This method allows you to create Hrefs
that are namespaced at any RouterSource instance.
```typescript
const nestedRouter = sources.router.path('/some').path('/path')
const href = nestedRouter.createHref('/unaware/of/nesting')
console.log(href) '/some/path/unaware/of/nesting')
```
#### `DefineReturn`
```typescript
export interface DefineReturn {
location: Location;
createHref: (path: Pathname) => Pathname;
path: string | null;
value: any | null;
}
```
#### `RouteDefinitions`
```typescript
export interface RouteDefinitions {
[key: Pathname]: any;
}
```
#### `RouterHOC`
```typescript
export interface RouterHOC {
<Sources, Sinks>(definitions: RouterDefinitions<Sources, Sinks>,
sources: RouterSources<Sources>): Stream<Sinks>;
<Sources, Sinks>(definitions: RouterDefinitions<Sources, Sinks>):
(sources: RouterSources<Sources>) => Stream<Sinks>;
}
```