UNPKG

hele-router

Version:
158 lines (148 loc) 4.43 kB
import { Component, Context, createElement, Fragment } from 'hele'; const _last = (arr) => arr[arr.length - 1]; const defaultRouterName = 'router'; class Router extends Component { constructor(props, context) { super(props, context); this.name = props.name; } render() { return (createElement(Context, { value: { [this.name]: this } }, this.props.children)); } } Router.defaultProps = { name: defaultRouterName }; class HistoryRouter extends Router { constructor(props, context) { super(props, context); this.onpopstate = (e) => { this.update(location.pathname); }; this.state = location.pathname; } onDidMount() { window.addEventListener('popstate', this.onpopstate); } onWillUnmount() { window.removeEventListener('popstate', this.onpopstate); } push(path) { if (!this.props.noHash && path.lastIndexOf('#') === -1) { path += location.hash; } history.pushState(null, '', path); this.update(location.pathname); } pop() { history.back(); } } const hashHistory = new Array(location.hash); class HashRouter extends Router { constructor(props, context) { super(props, context); this.onhashchange = () => { this.update(location.hash.slice(1)); }; this.state = _last(hashHistory).slice(1); } onDidMount() { window.addEventListener('hashchange', this.onhashchange); } onWillUnmount() { window.removeEventListener('hashchange', this.onhashchange); } push(path) { const hash = '#' + path; if (_last(hashHistory) !== hash) { location.hash = hash; hashHistory.push(hash); } } pop() { if (hashHistory.length > 1) { hashHistory.pop(); const hash = _last(hashHistory); location.hash = hash; } } } class Switch extends Router { constructor(props, context) { super(props, context); this._history = new Array(); this._history.push(this.state = props.path); } push(path) { const { _history } = this; if (_last(_history) !== path) { _history.push(path); this.update(path); } } pop() { const { _history } = this; if (_history.length > 1) { _history.pop(); const path = _last(_history); this.update(path); } } } Switch.defaultProps = { ...Router.defaultProps, path: '/' }; function testRoute(pathname, path, exact = false) { return exact ? pathname === path : pathname.indexOf(path) >= 0; } class Route extends Component { constructor(props, context) { super(props, context); this.state = testRoute(context[props.router].state, props.path, props.exact); } render() { const { props, state } = this; return props.render ? props.render(state) : (state && (props.component ? createElement(props.component) : createElement(Fragment, null, this.props.children))); } } Route.defaultProps = { router: defaultRouterName }; class Link extends Component { constructor(props, context) { super(props, context); this.onclick = this.onclick.bind(this); } render() { const { router, back, onclick, ...attrs } = this.props; return createElement("a", Object.assign({}, attrs, { onclick: this.onclick }), this.props.children); } onclick(event) { const { props } = this; let returnValue; if (props.onclick) { returnValue = props.onclick(event); } if (!event.defaultPrevented) { event.preventDefault(); const router = this.context[props.router]; if (props.back) { router.pop(); } else if (props.href) { router.push(props.href); } } return returnValue; } } Link.defaultProps = { href: 'javascript:;', back: false, router: defaultRouterName }; export { _last, defaultRouterName, Router, HistoryRouter, HashRouter, Switch, testRoute, Route, Link };