@storeon/router
Advanced tools
Comparing version 0.3.1 to 1.0.0
# Change Log | ||
This project adheres to [Semantic Versioning](http://semver.org/). | ||
## 1.0.0 | ||
* Rename named exports to `routerKey`, `routerChanged`, `routerNavigate` | ||
* Add ES modules support | ||
* Use ES2016 syntax | ||
* Update TypeScript definitions | ||
* Update docs | ||
* Reduce size | ||
## 0.3.1 | ||
@@ -5,0 +13,0 @@ * Reduce size |
@@ -1,17 +0,11 @@ | ||
import Storeon = require("storeon"); | ||
import { StoreonModule } from "storeon"; | ||
interface Callback { | ||
(...props: string[]): Object | ||
} | ||
export type Path = string | RegExp; | ||
export type Callback = (...props: string[]) => unknown; | ||
export type Route = [Path, Callback]; | ||
type Route = [string|RegExp, Callback] | ||
export function createRouter<State = unknown>(routes: Route[]): StoreonModule<State>; | ||
declare module StoreonRouter { | ||
export const key: unique symbol; | ||
export const changed: unique symbol; | ||
export const navigate: unique symbol; | ||
export function createRouter<State = unknown>(routes: Route[]): Storeon.Module<State>; | ||
} | ||
export = StoreonRouter | ||
export const routerKey: unique symbol; | ||
export const routerChanged: unique symbol; | ||
export const routerNavigate: unique symbol; |
133
index.js
@@ -1,42 +0,35 @@ | ||
var loc = location | ||
let loc = location | ||
/** | ||
* Change event | ||
* @type {symbol} | ||
*/ | ||
var change = Symbol() | ||
let change = Symbol() | ||
/** | ||
* Changed event | ||
* @type {symbol} | ||
*/ | ||
var changed = Symbol() | ||
let routerChanged = Symbol() | ||
/** | ||
* Navigate event | ||
* @type {symbol} | ||
*/ | ||
var navigate = Symbol() | ||
let routerNavigate = Symbol() | ||
/** | ||
* Router key on store | ||
* @type {symbol} | ||
* Router routerKey on store | ||
*/ | ||
var key = Symbol('route') | ||
let routerKey = Symbol('route') | ||
/** | ||
* Storeon module for URL routing | ||
* @param {Path[]} routes | ||
* @return {storeCallback} | ||
* @param {Route[]} routes | ||
*/ | ||
function createRouter (routes) { | ||
routes = routes || [] | ||
return function (store) { | ||
store.on('@init', function () { | ||
function createRouter (routes = []) { | ||
return store => { | ||
store.on('@init', () => { | ||
store.dispatch(change, parse(loc.pathname, routes)) | ||
}) | ||
store.on(navigate, function (state, path) { | ||
if (state[key].path !== path) { | ||
store.on(routerNavigate, (state, path) => { | ||
if (state[routerKey].path !== path) { | ||
history.pushState(null, null, path) | ||
@@ -46,23 +39,16 @@ } | ||
store.dispatch(change, parse(path, routes)) | ||
store.dispatch(changed, store.get()[key]) | ||
store.dispatch(routerChanged, store.get()[routerKey]) | ||
}) | ||
store.on(change, function (state, data) { | ||
var path = data[0] | ||
var route = routes[data[1]] | ||
var params = data[2] || [] | ||
var newState = {} | ||
newState[key] = { | ||
store.on(change, (state, [path, index, params = []]) => { | ||
let route = routes[index] | ||
let newState = {} | ||
newState[routerKey] = { | ||
match: false, | ||
path: path, | ||
params: params | ||
path, | ||
params | ||
} | ||
if (data.length > 1) { | ||
if (typeof route[1] === 'function') { | ||
newState[key].match = route[1].apply(null, params) | ||
} else { | ||
newState[key].match = route[1] || true | ||
} | ||
if (route) { | ||
newState[routerKey].match = route[1](...params) | ||
} | ||
@@ -73,3 +59,3 @@ | ||
document.documentElement.addEventListener('click', function (event) { | ||
document.documentElement.addEventListener('click', event => { | ||
if ( | ||
@@ -88,13 +74,13 @@ !event.defaultPrevented && | ||
event.preventDefault() | ||
var path = event.target.href.slice(loc.origin.length) | ||
store.dispatch(navigate, path) | ||
store.dispatch( | ||
routerNavigate, | ||
event.target.href.slice(loc.origin.length) | ||
) | ||
} | ||
}) | ||
window.addEventListener('popstate', function () { | ||
if (store.get()[key].path !== loc.pathname) { | ||
window.addEventListener('popstate', () => { | ||
if (store.get()[routerKey].path !== loc.pathname) { | ||
store.dispatch(change, parse(loc.pathname, routes)) | ||
store.dispatch(changed, store.get()[key]) | ||
store.dispatch(routerChanged, store.get()[routerKey]) | ||
} | ||
@@ -108,14 +94,12 @@ }) | ||
* @param {string} path | ||
* @param {Path[]} routes | ||
* @return {array} | ||
* @param {Route[]} routes | ||
* @return {[string, number, string[]]} | ||
*/ | ||
function parse (path, routes) { | ||
var normalized = path.replace(/(^\/|\/$)/g, '') | ||
let normalized = path.replace(/(^\/|\/$)/g, '') | ||
for (var index = 0; index < routes.length; index++) { | ||
var item = routes[index] | ||
for (let [index, [itemPath]] of routes.entries()) { | ||
if (typeof itemPath === 'string') { | ||
let checkPath = itemPath.replace(/(^\/|\/$)/g, '') | ||
if (typeof item[0] === 'string') { | ||
var checkPath = item[0].replace(/(^\/|\/$)/g, '') | ||
if (checkPath === normalized) { | ||
@@ -125,11 +109,11 @@ return [path, index] | ||
if (checkPath.indexOf('*') >= 0) { | ||
var prepareRe = checkPath | ||
if (checkPath.includes('*')) { | ||
let prepareRe = checkPath | ||
.replace(/[\s!#$()+,.:<=?[\\\]^{|}]/g, '\\$&') | ||
.replace(/\*/g, '([^/]*)') | ||
var re = RegExp('^' + prepareRe + '$', 'i') | ||
var match = normalized.match(re) | ||
let re = RegExp('^' + prepareRe + '$', 'i') | ||
let match = normalized.match(re) | ||
if (match) { | ||
return [path, index, [].concat(match).slice(1)] | ||
return [path, index, match.slice(1)] | ||
} | ||
@@ -139,6 +123,6 @@ } | ||
if (item[0] instanceof RegExp) { | ||
var matchRE = normalized.match(item[0]) | ||
if (itemPath instanceof RegExp) { | ||
let matchRE = normalized.match(itemPath) | ||
if (matchRE) { | ||
return [path, index, [].concat(matchRE).slice(1)] | ||
return [path, index, matchRE.slice(1)] | ||
} | ||
@@ -151,28 +135,7 @@ } | ||
module.exports = { | ||
navigate: navigate, | ||
changed: changed, | ||
key: key, | ||
createRouter: createRouter | ||
export { | ||
routerNavigate, | ||
routerChanged, | ||
routerKey, | ||
createRouter | ||
} | ||
/** | ||
* @typedef {array} Path | ||
* @property {string | RegExp} 0 | ||
* @property {?function} 1 | ||
*/ | ||
/** | ||
* @private | ||
* @callback storeCallback | ||
* @param {Store} store | ||
*/ | ||
/** | ||
* @private | ||
* @name Store | ||
* @class | ||
* @method get | ||
* @method dispatch | ||
* @method on | ||
*/ |
{ | ||
"name": "@storeon/router", | ||
"version": "0.3.1", | ||
"version": "1.0.0", | ||
"description": "Storeon module for URL routing", | ||
"main": "index.js", | ||
"main": "index.cjs", | ||
"types": "./index.d.ts", | ||
"author": "Ivan Solovev <ivan@solovev.one>", | ||
"license": "MIT" | ||
} | ||
"license": "MIT", | ||
"type": "module", | ||
"module": "index.js", | ||
"exports": { | ||
"./package.json": "./package.json", | ||
".": { | ||
"require": "./index.cjs", | ||
"import": "./index.js" | ||
} | ||
} | ||
} |
@@ -8,3 +8,3 @@ # Storeon Router | ||
It size is 650 bytes (minified and gzipped) and uses [Size Limit] to control size. | ||
It size is 570 bytes (minified and gzipped) and uses [Size Limit] to control size. | ||
@@ -26,14 +26,14 @@ [Storeon]: https://github.com/storeon/storeon | ||
If you want to use the router you should import the `router.createRouter` from `@storeon/router` and add this module to `createStore`. | ||
If you want to use the router you should import the `createRouter` from `@storeon/router` and add this module to `createStoreon`. | ||
```js | ||
import createStore from 'storeon' | ||
import useStoreon from 'storeon/react' | ||
import router from '@storeon/router' | ||
import { createStoreon } from 'storeon' | ||
import { createRouter, routerChanged, routerKey } from '@storeon/router' | ||
const store = createStore([ | ||
router.createRouter([ | ||
const store = createStoreon([ | ||
createRouter([ | ||
['/', () => ({ page: 'home' })], | ||
['/blog', () => ({ page: 'blog' })], | ||
['/blog/post/*', (id) => ({ page: 'post', id })], | ||
[ | ||
@@ -46,59 +46,29 @@ /^blog\/post\/(\d+)\/(\d+)$/, | ||
function Root() { | ||
const { [router.key]: route } = useStoreon(router.key) | ||
setData(store.get()[routerKey]) | ||
switch (route.match.page) { | ||
case "home": | ||
return <Home/> | ||
store.on(routerChanged, function (_, data) { | ||
setData(data) | ||
}) | ||
case "blog": | ||
return <Blog/> | ||
case "post": | ||
return <Post year={route.match.year} month={route.match.month} id={route.match.id}/> | ||
default: | ||
return <NotFound/> | ||
} | ||
function setData (data) { | ||
document | ||
.querySelector('.data') | ||
.innerText = JSON.stringify(data) | ||
} | ||
store.dispatch(router.navigate, '/') | ||
``` | ||
## Usage with [Svelte](https://github.com/storeon/svelte): | ||
If you want to use the router with Svelte you should import the `router.createRouter` from [@storeon/router](https://github.com/storeon/router) and add this module to `createSvelteStore` instead of `createStore` | ||
#### `store.js` | ||
```js | ||
import { createSvelteStore } from "@storeon/svelte"; | ||
import { createRouter } from '@storeon/router' | ||
## Examples | ||
const connect = createSvelteStore([ | ||
createRouter([ | ||
['/', () => ({ page: 'home' })], | ||
['/blog', () => ({ page: 'blog' })], | ||
]) | ||
]) | ||
``` | ||
* [Vanilla](./examples/vanilla/) | ||
* [React/Preact](./examples/react/) | ||
* [Svelte](./examples/svelte/) | ||
And use it like: | ||
#### `App.svelte` | ||
```svelte | ||
<script> | ||
import { connect } from "./store.js"; | ||
import router from "@storeon/router" | ||
const moduleRouter = connect(router.key) | ||
</script> | ||
You can access the router like default svelte store via $: | ||
{$moduleRouter.match.page} | ||
``` | ||
## API | ||
```js | ||
import router from '@storeon/router' | ||
import { createRouter } from '@storeon/router' | ||
const moduleRouter = router.createRouter([ | ||
const moduleRouter = createRouter([ | ||
[path, callback] | ||
@@ -108,3 +78,3 @@ ]) | ||
Function `router.createRouter` could have options: | ||
Function `createRouter` could have options: | ||
@@ -114,10 +84,11 @@ * __path__: path name can be a string or RegExp. | ||
`router.key` – key for store. | ||
`routerKey` – key for store. | ||
`router.navigate` – navigation action. | ||
`routerNavigate` – navigation action. | ||
`router.changed` – change event of pathname. | ||
`routerChanged` – change event of pathname. | ||
### Ignore link | ||
Add `data-ignore-router` attribute to the link so that the router ignores it. | ||
@@ -124,0 +95,0 @@ |
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
13366
8
350
1
Yes
105
1