text: import { Component, cloneElement, createElement, toChildArray } from '/lib/preact.js';
  
  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) {
  	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) {
  	return (
  		(a.rank < b.rank) ? 1 :
  			(a.rank > b.rank) ? -1 :
  				(a.index - b.index)
  	);
  }
  
  // filter out VNodes without attributes (which are unrankeable), and add `index`/`rank` properties to be used in sorting.
  function prepareVNodeForRanking(vnode, index) {
  	vnode.index = index;
  	vnode.rank = rankChild(vnode);
  	return vnode.props;
  }
  
  function segmentize(url) {
  	return url.replace(/(^\/+|\/+$)/g, '').split('/');
  }
  
  function rankSegment(segment) {
  	return segment.charAt(0) == ':' ? (1 + '*+?'.indexOf(segment.charAt(segment.length - 1))) || 4 : 5;
  }
  
  function rank(path) {
  	return segmentize(path).map(rankSegment).join('');
  }
  
  function rankChild(vnode) {
  	return vnode.props.default ? 0 : rank(vnode.props.path);
  }
  
  var customHistory = null;
  
  var ROUTERS = [];
  
  var subscribers = [];
  
  var EMPTY = {};
  
  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.ctrlKey || e.metaKey || e.altKey || e.shiftKey || e.button !== 0) { return; }
  	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')) {
  			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 () {
  				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) {
  		var children = toChildArray(this.props.children);
  		return this.getMatchingChildren(children, url, false).length > 0;
  	};
  
  	/** Re-render children with a new URL to match against. */
  	Router.prototype.routeTo = function routeTo(url) {
  		this.setState({ url: url });
  
  		var didRoute = this.canRoute(url);
  
  		// trigger a manual re-route if we're not in the middle of an update:
  		if (!this.updating) { this.forceUpdate(); }
  
  		return 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
  			.filter(prepareVNodeForRanking)
  			.sort(pathRankSort)
  			.map(function (vnode) {
  				var matches = exec(url, vnode.props.path, vnode.props);
  				if (matches) {
  					if (invoke !== false) {
  						var newProps = { url: url, matches: matches };
  						assign(newProps, matches);
  						delete newProps.ref;
  						delete newProps.key;
  						return cloneElement(vnode, newProps);
  					}
  					return vnode;
  				}
  			}).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(toChildArray(children), url, true);
  
  		var current = active[0] || null;
  
  		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 (
  		createElement('a', assign({ onClick: handleLinkClick }, props))
  	);
  };
  
  var Route = function (props) { return createElement(props.component, props); };
  
  Router.subscribers = subscribers;
  Router.getCurrentUrl = getCurrentUrl;
  Router.route = route;
  Router.Router = Router;
  Router.Route = Route;
  Router.Link = Link;
  Router.exec = exec;
  
  export { subscribers, getCurrentUrl, route, Router, Route, Link, exec }; export default Router;
  