0.0.6 • Published 8 years ago

wrouter v0.0.6

Weekly downloads
16
License
ISC
Repository
github
Last release
8 years ago

wrouter

demo

Router state machine for virtual doms. It's a wrapper around single-page and catch-links for easier client side routing. It also works in Node if you pass in a route event.

install

$ npm install wrouter

example

Node:

var Router = require('wrouter');
var struct = require('observ-struct');
var value = require('observ');
var assert = require('assert');

var routeEvent = value('');

var routerState = Router({
  routeHash: {
    '/animals/:id': {
      component: {
        state: struct({ example: 'my data' }),
        render: function renderMyComponent(state) {
          assert(state.example === 'my data');
        }
      },
      // do anything that needs to happen before component.render is called
      routeFn: function(params, done) {
        console.log(params);
        done();
      }
    }
  },
  // pass in an event implemented like `observ`. If this is omitted the
  // router will listen for click events on document.body
  // (via `catch-links`)
  event: routeEvent
});

routerState(function onChange(state) {
  var view = Router.route(state);
  // {
  //    state: { example: 'my data' },
  //    render: renderMyComponent
  // }
  view.render(view.state);
});


routeEvent.set('/animals/3');   // { id: '3' }
try {
  routeEvent.set('no-match');
}
catch(err) {
  console.log(err);
  // [Error: router: no match found]
}

Browser:

var Loop = require('main-loop');
var vdom = require('virtual-dom');
var h = vdom.h;
var struct = require('observ-struct');
var value = require('observ');
var noop = function(){};

var Router = require('../Router.js');
var components = require('./components');

var animalItemEvent = struct({});

function fetchAnimal(id, cb) {
  setTimeout(function () {
    cb({
      id: id,
      _name: 'iguana',
      type: 'reptile'
    });
  }, 500);
}

var app = App();
var loop = Loop( app(), renderApp, vdom);
document.getElementById('content').appendChild(loop.target);
app(loop.update);

// root component
function App() {

  var routeHash = {
    '/': {
      component: {
        state: components.Home({home: 'home state'}),
        render: components.Home.render
      }
    },
    '/animals': {
      component: {
        state: components.Animals(),
        render: components.Animals.render
      }
    },
    '/animals/:id': {
      component: {
        state: components.AnimalItem({
          event: animalItemEvent
        }),
        render: components.AnimalItem.render
      },

      // do anything that needs to be done before the view is rendered
      routeFn: function(params, done) {
        if ( !state.loading() ) state.loading.set(true);
        fetchAnimal(params.id, function(animal) {
          if (state.loading) state.loading.set(false);
          animalItemEvent.set(animal);
          done();
        });
      }
    }
  };

  var state = struct({
    loading: value(false),
    router: Router({
      routeHash: routeHash
    })
  });

  return state;
}

function renderApp(state) {
  var page = Router.route(state.router);
  return h('div', {
    style: { }
  }, [
    h('div', {style: {
      width: '50%',
      display: 'inline-block'
    }}, [
      menu(),
      page ? page.render(page.state) : '',
    ]),
    h('div.loading', {
      style: {
        width: '30%',
        display: state.loading ? 'inline-block' : 'none',
        textAlign: 'center',
        fontSize: '2em',
      }
    }, ['loading'])
  ]);

  function menu() {
    return h('ul', [
      h('li', [
        h('a', {
          href: '/'
        }, 'Home')
      ]),
      h('li', [
        h('a', {
          href: '/animals'
        }, 'Animals')
      ]),
      h('li', [
        h('a', {
          href: '/animals/1'
        }, 'Animal Item')
      ])
    ]);
  }
}