@motorcycle/router

Standard Router Driver for Motorcycle.js

Stats

stars 🌟issues ⚠️updated 🛠created 🐣size 🏋️‍♀️
10Apr 26, 2017Nov 18, 2016Minified + gzip package size for @motorcycle/router in KB

Readme

@motorcycle/router

Standard Router Driver for Motorcycle.js

A driver built on top of @motorcycle/history and switch-path to ease the pain of routing. Works server-side and in browsers!

Let me have it!

npm install --save @motorcycle/router

Basic Usage

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

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.

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.

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.

const nestedRouter = sources.router.path('/some').path('/path')

const href = nestedRouter.createHref('/unaware/of/nesting')

console.log(href) '/some/path/unaware/of/nesting')

DefineReturn

export interface DefineReturn {
  location: Location;
  createHref: (path: Pathname) => Pathname;
  path: string | null;
  value: any | null;
}

RouteDefinitions

export interface RouteDefinitions {
  [key: Pathname]: any;
}

RouterHOC

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>;
}

If you find any bugs or have a feature request, please open an issue on github!

The npm package download data comes from npm's download counts api and package details come from npms.io.