# uri-router

> A small framework for building URI driven DOM applications

Latest version **3.0.5** (published 2017-01-19) · WTFPL license · 0 weekly downloads

## Install

```sh
npm install uri-router
pnpm add uri-router
yarn add uri-router
bun add uri-router
```

## Health

**Score 15/100 (F)** — status: abandoned.

Positive: no vulnerabilities.

Warnings: low downloads; no types; no esm support.

Negative: abandoned; low maintenance score.

## Facts

| | |
|---|---|
| Version | 3.0.5 |
| Published | 2017-01-19 |
| First published | 2015-11-22 |
| Weekly downloads | 0 |
| License | WTFPL |
| TypeScript types | none |
| Module format | CommonJS |
| Dependencies | 0 |
| Known vulnerabilities | 0 |
| Install scripts | no |
| GitHub stars | 0 |
| Author | Jesse Tane |
| Maintainers | jessetane |
| Keywords | router, pushState, history, uri, url |

## Links

- npm: https://www.npmjs.com/package/uri-router
- Repository: https://github.com/jessetane/uri-router
- Homepage: https://github.com/jessetane/uri-router#readme
- Issues: https://github.com/jessetane/uri-router/issues
- npm.io page: https://npm.io/package/uri-router

## Alternatives

- [express-promise-router](https://npm.io/package/express-promise-router.md) — 736.1K weekly downloads
- [next-usequerystate](https://npm.io/package/next-usequerystate.md) — 29.8K weekly downloads
- [@bitkyc08/opencodex](https://npm.io/package/@bitkyc08/opencodex.md) — 4.6K weekly downloads
- [lynkr](https://npm.io/package/lynkr.md) — 575 weekly downloads
- [baremetal.js](https://npm.io/package/baremetal.js.md) — 42 weekly downloads

## Recent versions

- 3.0.5 (latest) — 2017-01-19
- 3.0.4 — 2017-01-16
- 3.0.3 — 2016-11-15
- 3.0.2 — 2016-11-15
- 3.0.1 — 2016-03-27
- 3.0.0 — 2016-02-21
- 2.0.1 — 2015-12-11
- 2.0.0 — 2015-12-11
- 1.2.4 — 2015-11-30
- 1.2.0 — 2015-11-24
- 1.1.1 — 2015-11-24
- 1.0.5 — 2015-11-22
- 1.0.4 — 2015-11-22
- 1.0.3 — 2015-11-22
- 1.0.2 — 2015-11-22
- … 1 more at https://npm.io/package/uri-router/versions

## README

# uri-router [![npm](http://img.shields.io/npm/v/uri-router.svg?style=flat-square)](http://www.npmjs.org/uri-router) [![tests](https://img.shields.io/travis/jessetane/uri-router/master.svg?style=flat-square)](https://travis-ci.org/jessetane/uri-router)
A small framework for building URI driven DOM applications.

[![saucelabs](https://saucelabs.com/browser-matrix/uri-router.svg)](https://saucelabs.com/u/uri-router)

## Example
index.html
``` html
<!doctype html>
<html>
  <body>
    <nav>
      <a href="/">home</a> |
      <a href="/about">about</a> |
      <a href="/contact">contact</a>
    </nav>
    <div id="pages"></div>
  </body>
  <script type="text/javascript" src="/app.js"></script>
</html>
```
app.js
``` js
var router = require('uri-router')
var nav = require('./nav')
var home = require('./home')
var about = require('./about')
var contact = require('./contact')

router({
  routes: [
    ['.*', nav]
  ]
})

router({
  watch: 'pathname',
  outlet: document.querySelector('#pages'),
  routes: [
    ['/',           home],
    ['/about',     about],
    ['/contact', contact]
  ]
})
```

nav.js (a view that's already on the DOM)
``` js
module.exports = document.querySelector('nav')

var qsa = require('qsa-es5')

module.exports.show = function (uri) {
  qsa('a', this).forEach(function (a) {
    var active = a.getAttribute('href') === uri.pathname
    a.style.textDecoration = active ? 'underline' : 'none'
  })
}
```

home.js (a plain DOM element as a view)
``` js
module.exports = function () {
  var el = document.createElement('H1')
  el.textContent = 'Home'
  return el
}
```

about.js (a web component as a view)
``` js
var About = {
  prototype: Object.create(window.HTMLElement.prototype)
}

About.prototype.createdCallback = function () {
  var shadow = this.createShadowRoot()
  shadow.innerHTML = '<h1>About</h1>'
}

module.exports = document.registerElement('about-component', About)
```

contact.js (a view that uses lifecycle hooks to transition in and out)
``` js
module.exports = function () {
  var el = document.createElement('div')
  el.innerHTML = '<h1>Contact</h1>'
  el.show = show
  el.hide = hide
  el.style.transition = 'opacity 0.5s'
  return el
}

function show () {
  window.getComputedStyle(this).opacity
  this.style.opacity = '1'
}

function hide (uri, cb) {
  this.style.opacity = '0'
  this.addEventListener('transitionend', cb)
}
```

The code above is pretty basic, check out [the example app](https://github.com/jessetane/uri-router/tree/master/example) for fancier things:

``` shell
$ npm run example
```

## Test
``` shell
$ npm run test-local
$ # to run the tests at sauce, open a sauce-connect tunnel and do:
$ SAUCE_USERNAME=x SAUCE_ACCESS_KEY=y npm run test
```

## Require

### `var Router = require('uri-router')`
Returns a function for creating routers. The first time `uri-router` is required, it will globally hijack all link clicks and form submissions targeting the origin and start listening for the `popstate` event.

## Static methods
It's critical you do not use `window.history.{pushState,replaceState,go,back}()` directly! Use the static methods listed here instead.

### `Router.push(location, [replace])`  
Update `window.location`.
  * `location` String
  * `replace` Boolean; indicates to use replaceState instead of pushState

### `Router.replace(location)`
Shortcut for `Router.push(location, true)`.

### `Router.pop()`
Like `window.history.back()` put queued properly.

### `Router.search(query, [replace])`  
Update `window.location.search` without clobbering the existing query.
> example: assuming the search string is set to `?a=1`, calling `Router.search({ b: 2 })` would change it to `?a=1&b=2`.

## Instance methods

### `var r = Router(opts)`
The constructor. `opts` is augmented, tracked and returned as `r`. Beware, `r` is NOT actually an instance of `Router`! I am open to changing this if there is a good reason.

### `r.destroy()`
Hide any active views and stop the instance from updating on `{push,replace,pop}state`.

## Instance properties

### `r.watch`
Should be set to the name of a property on `window.location`, generally "pathname" or "hash"

### `r.routes`
An array of regex / handler pairs like: `['regex', handler]`. The handler can be an instance of HTMLElement, a newable constructor that inherits from HTMLElement, or a function with signature `(uri, next)`. Handlers that are plain functions should either call `next` to be treated as middleware (falling through to succeeding routes) or return an instance of HTMLElement, but not both.
> views generated by route handlers can optionally define `show()` and `hide()` methods, see [lifecycle hooks](#lifecycle-hooks) for more details.

### `r.outlet`
An optional DOM element. If an outlet is specified, location changes will trigger the removal of any existing elements, and the appending of any elements generated by the matched handler. If the same handler is matched more than once in a row, and `handler.reusable === true`, the existing view will simply get a `show()` hook rather than being removed and created again from scratch.

### `r.base`
An optional prefix to ignore for `r.watch`. Useful for building abstract views with nested routers.

## Lifecycle hooks
Any time `window.location` changes, all active views should expect to receive one or more of the following (optional) hooks:

### `view.show(uri)`
Called on all active views when `window.location` changes. See [URI Properties](#uri-properties) for properties available on `uri`.

### `view.hide(uri, cb)`
Called after a view becomes inactive, but just before it is removed from the DOM. If the hide implementation accepts a callback, (and the router specifies an `outlet`) the router will defer removing the view from the DOM until the callback is executed.

## URI properties
`URI` objects are passed to route handlers and [lifecycle hooks](#lifecycle-hooks). They define most of the properties described in the [URL spec](https://url.spec.whatwg.org) and some `Router` specific properties described here:

### `init`
True when `window.location` has not changed since the page loaded.

### `back`
True when the browser's back button has been clicked or `Router.pop()` was called.

### `replace`
True when `Router.replace` initiated the location change.

### `watch`
Alias for the dispatching router's `watch` property.

### `base`
Alias for the dispatching router's `base` property.

### `top`
If there are any capture groups in the route regex, this will be set to the value of the first group. You can use this to set `r.base` on nested routers.

### `params`
An array of the capture group values from the route regex, excepting the first group, which is considered the `base` - see above.

### `query`
A parsed querystring object.

## Releases
* [3.0.1](https://github.com/jessetane/uri-router/releases)
  * Added option `Router.replaceOnClick` to replace instead of push by default when handling link clicks
* [3.x](https://github.com/jessetane/uri-router/releases)
  * Changed `uri.base` semantics and added a corresponding `uri.top` property
* [2.x](https://github.com/jessetane/uri-router/releases)
  * Changed `uri.init` semantics
  * Expose the current uri
  * Set default watch property to "href"
* [1.x](https://github.com/jessetane/uri-router/releases)
  * Complete rewrite, November 2015
* [0.x](https://github.com/jessetane/uri-router/releases)
  * Initial prototype, August 2014

## License
Copyright © 2014 Jesse Tane <jesse.tane@gmail.com>

This work is free. You can redistribute it and/or modify it under the
terms of the [WTFPL](http://www.wtfpl.net/txt/copying).

No Warranty. The Software is provided "as is" without warranty of any kind, either express or implied, including without limitation any implied warranties of condition, uninterrupted use, merchantability, fitness for a particular purpose, or non-infringement.

---
_Source: https://npm.io/package/uri-router · Machine-readable twin of the npm.io package page. Health data is recomputed on every publish._
