UNPKG

preact-material-components

Version:
356 lines (285 loc) 8.68 kB
import { Component, cloneElement, h } from 'preact'; var EMPTY$1 = {}; function assign(obj, props) { // eslint-disable-next-line guard-for-in for (var i in props) { obj[i] = props[i]; } return obj; } function exec(url, route, opts) { if ( opts === void 0 ) opts=EMPTY$1; var reg = /(?:\?([^#]*))?(#.*)?$/, c = url.match(reg), matches = {}, ret; if (c && c[1]) { var p = c[1].split('&'); for (var i=0; i<p.length; i++) { var r = p[i].split('='); matches[decodeURIComponent(r[0])] = decodeURIComponent(r.slice(1).join('=')); } } url = segmentize(url.replace(reg, '')); route = segmentize(route || ''); var max = Math.max(url.length, route.length); for (var i$1=0; i$1<max; i$1++) { if (route[i$1] && route[i$1].charAt(0)===':') { var param = route[i$1].replace(/(^\:|[+*?]+$)/g, ''), flags = (route[i$1].match(/[+*?]+$/) || EMPTY$1)[0] || '', plus = ~flags.indexOf('+'), star = ~flags.indexOf('*'), val = url[i$1] || ''; if (!val && !star && (flags.indexOf('?')<0 || plus)) { ret = false; break; } matches[param] = decodeURIComponent(val); if (plus || star) { matches[param] = url.slice(i$1).map(decodeURIComponent).join('/'); break; } } else if (route[i$1]!==url[i$1]) { ret = false; break; } } if (opts.default!==true && ret===false) { return false; } return matches; } function pathRankSort(a, b) { var aAttr = a.attributes || EMPTY$1, bAttr = b.attributes || EMPTY$1; if (aAttr.default) { return 1; } if (bAttr.default) { return -1; } var diff = rank(aAttr.path) - rank(bAttr.path); return diff || (aAttr.path.length - bAttr.path.length); } function segmentize(url) { return strip(url).split('/'); } function rank(url) { return (strip(url).match(/\/+/g) || '').length; } function strip(url) { return url.replace(/(^\/+|\/+$)/g, ''); } var customHistory = null; var ROUTERS = []; var subscribers = []; var EMPTY = {}; function isPreactElement(node) { return node.__preactattr_!=null || typeof Symbol!=='undefined' && node[Symbol.for('preactattr')]!=null; } function setUrl(url, type) { if ( type === void 0 ) type='push'; if (customHistory && customHistory[type]) { customHistory[type](url); } else if (typeof history!=='undefined' && history[type+'State']) { history[type+'State'](null, null, url); } } function getCurrentUrl() { var url; if (customHistory && customHistory.location) { url = customHistory.location; } else if (customHistory && customHistory.getCurrentLocation) { url = customHistory.getCurrentLocation(); } else { url = typeof location!=='undefined' ? location : EMPTY; } return ("" + (url.pathname || '') + (url.search || '')); } function route(url, replace) { if ( replace === void 0 ) replace=false; if (typeof url!=='string' && url.url) { replace = url.replace; url = url.url; } // only push URL into history if we can handle it if (canRoute(url)) { setUrl(url, replace ? 'replace' : 'push'); } return routeTo(url); } /** Check if the given URL can be handled by any router instances. */ function canRoute(url) { for (var i=ROUTERS.length; i--; ) { if (ROUTERS[i].canRoute(url)) { return true; } } return false; } /** Tell all router instances to handle the given URL. */ function routeTo(url) { var didRoute = false; for (var i=0; i<ROUTERS.length; i++) { if (ROUTERS[i].routeTo(url)===true) { didRoute = true; } } for (var i$1=subscribers.length; i$1--; ) { subscribers[i$1](url); } return didRoute; } function routeFromLink(node) { // only valid elements if (!node || !node.getAttribute) { return; } var href = node.getAttribute('href'), target = node.getAttribute('target'); // ignore links with targets and non-path URLs if (!href || !href.match(/^\//g) || (target && !target.match(/^_?self$/i))) { return; } // attempt to route, if no match simply cede control to browser return route(href); } function handleLinkClick(e) { if (e.button==0) { routeFromLink(e.currentTarget || e.target || this); return prevent(e); } } function prevent(e) { if (e) { if (e.stopImmediatePropagation) { e.stopImmediatePropagation(); } if (e.stopPropagation) { e.stopPropagation(); } e.preventDefault(); } return false; } function delegateLinkHandler(e) { // ignore events the browser takes care of already: if (e.ctrlKey || e.metaKey || e.altKey || e.shiftKey || e.button!==0) { return; } var t = e.target; do { if (String(t.nodeName).toUpperCase()==='A' && t.getAttribute('href') && isPreactElement(t)) { if (t.hasAttribute('native')) { return; } // if link is handled by the router, prevent browser defaults if (routeFromLink(t)) { return prevent(e); } } } while ((t=t.parentNode)); } var eventListenersInitialized = false; function initEventListeners() { if (eventListenersInitialized){ return; } if (typeof addEventListener==='function') { if (!customHistory) { addEventListener('popstate', function () { return routeTo(getCurrentUrl()); }); } addEventListener('click', delegateLinkHandler); } eventListenersInitialized = true; } var Router = (function (Component$$1) { function Router(props) { Component$$1.call(this, props); if (props.history) { customHistory = props.history; } this.state = { url: props.url || getCurrentUrl() }; initEventListeners(); } if ( Component$$1 ) Router.__proto__ = Component$$1; Router.prototype = Object.create( Component$$1 && Component$$1.prototype ); Router.prototype.constructor = Router; Router.prototype.shouldComponentUpdate = function shouldComponentUpdate (props) { if (props.static!==true) { return true; } return props.url!==this.props.url || props.onChange!==this.props.onChange; }; /** Check if the given URL can be matched against any children */ Router.prototype.canRoute = function canRoute (url) { return this.getMatchingChildren(this.props.children, url, false).length > 0; }; /** Re-render children with a new URL to match against. */ Router.prototype.routeTo = function routeTo (url) { this._didRoute = false; this.setState({ url: url }); // if we're in the middle of an update, don't synchronously re-route. if (this.updating) { return this.canRoute(url); } this.forceUpdate(); return this._didRoute; }; Router.prototype.componentWillMount = function componentWillMount () { ROUTERS.push(this); this.updating = true; }; Router.prototype.componentDidMount = function componentDidMount () { var this$1 = this; if (customHistory) { this.unlisten = customHistory.listen(function (location) { this$1.routeTo(("" + (location.pathname || '') + (location.search || ''))); }); } this.updating = false; }; Router.prototype.componentWillUnmount = function componentWillUnmount () { if (typeof this.unlisten==='function') { this.unlisten(); } ROUTERS.splice(ROUTERS.indexOf(this), 1); }; Router.prototype.componentWillUpdate = function componentWillUpdate () { this.updating = true; }; Router.prototype.componentDidUpdate = function componentDidUpdate () { this.updating = false; }; Router.prototype.getMatchingChildren = function getMatchingChildren (children, url, invoke) { return children.slice().sort(pathRankSort).map( function (vnode) { var attrs = vnode.attributes || {}, path = attrs.path, matches = exec(url, path, attrs); if (matches) { if (invoke!==false) { var newProps = { url: url, matches: matches }; assign(newProps, matches); return cloneElement(vnode, newProps); } return vnode; } return false; }).filter(Boolean); }; Router.prototype.render = function render (ref, ref$1) { var children = ref.children; var onChange = ref.onChange; var url = ref$1.url; var active = this.getMatchingChildren(children, url, true); var current = active[0] || null; this._didRoute = !!current; var previous = this.previousUrl; if (url!==previous) { this.previousUrl = url; if (typeof onChange==='function') { onChange({ router: this, url: url, previous: previous, active: active, current: current }); } } return current; }; return Router; }(Component)); var Link = function (props) { return ( h('a', assign({ onClick: handleLinkClick }, props)) ); }; var Route = function (props) { return h(props.component, props); }; Router.subscribers = subscribers; Router.getCurrentUrl = getCurrentUrl; Router.route = route; Router.Router = Router; Router.Route = Route; Router.Link = Link; export { subscribers, getCurrentUrl, route, Router, Route, Link };export default Router; //# sourceMappingURL=preact-router.es.js.map