var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
    return new (P || (P = Promise))(function (resolve, reject) {
        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
        function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
};
var __generator = (this && this.__generator) || function (thisArg, body) {
    var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
    return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
    function verb(n) { return function (v) { return step([n, v]); }; }
    function step(op) {
        if (f) throw new TypeError("Generator is already executing.");
        while (_) try {
            if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
            if (y = 0, t) op = [op[0] & 2, t.value];
            switch (op[0]) {
                case 0: case 1: t = op; break;
                case 4: _.label++; return { value: op[1], done: false };
                case 5: _.label++; y = op[1]; op = [0]; continue;
                case 7: op = _.ops.pop(); _.trys.pop(); continue;
                default:
                    if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
                    if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
                    if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
                    if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
                    if (t[2]) _.ops.pop();
                    _.trys.pop(); continue;
            }
            op = body.call(thisArg, _);
        } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
        if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
    }
};
import { r as registerInstance, c as createEvent, h, g as getElement } from './chunk-82a2445c.js';
import { c as createCommonjsModule, a as commonjsGlobal } from './chunk-d7ac2f15.js';
var page = createCommonjsModule(function (module, exports) {
    (function (global, factory) {
        module.exports = factory();
    }(commonjsGlobal, (function () {
        var isarray = Array.isArray || function (arr) {
            return Object.prototype.toString.call(arr) == '[object Array]';
        };
        /**
         * Expose `pathToRegexp`.
         */
        var pathToRegexp_1 = pathToRegexp;
        var parse_1 = parse;
        var compile_1 = compile;
        var tokensToFunction_1 = tokensToFunction;
        var tokensToRegExp_1 = tokensToRegExp;
        /**
         * The main path matching regexp utility.
         *
         * @type {RegExp}
         */
        var PATH_REGEXP = new RegExp([
            // Match escaped characters that would otherwise appear in future matches.
            // This allows the user to escape special characters that won't transform.
            '(\\\\.)',
            // Match Express-style parameters and un-named parameters with a prefix
            // and optional suffixes. Matches appear as:
            //
            // "/:test(\\d+)?" => ["/", "test", "\d+", undefined, "?", undefined]
            // "/route(\\d+)"  => [undefined, undefined, undefined, "\d+", undefined, undefined]
            // "/*"            => ["/", undefined, undefined, undefined, undefined, "*"]
            '([\\/.])?(?:(?:\\:(\\w+)(?:\\(((?:\\\\.|[^()])+)\\))?|\\(((?:\\\\.|[^()])+)\\))([+*?])?|(\\*))'
        ].join('|'), 'g');
        /**
         * Parse a string for the raw tokens.
         *
         * @param  {String} str
         * @return {Array}
         */
        function parse(str) {
            var tokens = [];
            var key = 0;
            var index = 0;
            var path = '';
            var res;
            while ((res = PATH_REGEXP.exec(str)) != null) {
                var m = res[0];
                var escaped = res[1];
                var offset = res.index;
                path += str.slice(index, offset);
                index = offset + m.length;
                // Ignore already escaped sequences.
                if (escaped) {
                    path += escaped[1];
                    continue;
                }
                // Push the current path onto the tokens.
                if (path) {
                    tokens.push(path);
                    path = '';
                }
                var prefix = res[2];
                var name = res[3];
                var capture = res[4];
                var group = res[5];
                var suffix = res[6];
                var asterisk = res[7];
                var repeat = suffix === '+' || suffix === '*';
                var optional = suffix === '?' || suffix === '*';
                var delimiter = prefix || '/';
                var pattern = capture || group || (asterisk ? '.*' : '[^' + delimiter + ']+?');
                tokens.push({
                    name: name || key++,
                    prefix: prefix || '',
                    delimiter: delimiter,
                    optional: optional,
                    repeat: repeat,
                    pattern: escapeGroup(pattern)
                });
            }
            // Match any characters still remaining.
            if (index < str.length) {
                path += str.substr(index);
            }
            // If the path exists, push it onto the end.
            if (path) {
                tokens.push(path);
            }
            return tokens;
        }
        /**
         * Compile a string to a template function for the path.
         *
         * @param  {String}   str
         * @return {Function}
         */
        function compile(str) {
            return tokensToFunction(parse(str));
        }
        /**
         * Expose a method for transforming tokens into the path function.
         */
        function tokensToFunction(tokens) {
            // Compile all the tokens into regexps.
            var matches = new Array(tokens.length);
            // Compile all the patterns before compilation.
            for (var i = 0; i < tokens.length; i++) {
                if (typeof tokens[i] === 'object') {
                    matches[i] = new RegExp('^' + tokens[i].pattern + '$');
                }
            }
            return function (obj) {
                var path = '';
                var data = obj || {};
                for (var i = 0; i < tokens.length; i++) {
                    var token = tokens[i];
                    if (typeof token === 'string') {
                        path += token;
                        continue;
                    }
                    var value = data[token.name];
                    var segment;
                    if (value == null) {
                        if (token.optional) {
                            continue;
                        }
                        else {
                            throw new TypeError('Expected "' + token.name + '" to be defined');
                        }
                    }
                    if (isarray(value)) {
                        if (!token.repeat) {
                            throw new TypeError('Expected "' + token.name + '" to not repeat, but received "' + value + '"');
                        }
                        if (value.length === 0) {
                            if (token.optional) {
                                continue;
                            }
                            else {
                                throw new TypeError('Expected "' + token.name + '" to not be empty');
                            }
                        }
                        for (var j = 0; j < value.length; j++) {
                            segment = encodeURIComponent(value[j]);
                            if (!matches[i].test(segment)) {
                                throw new TypeError('Expected all "' + token.name + '" to match "' + token.pattern + '", but received "' + segment + '"');
                            }
                            path += (j === 0 ? token.prefix : token.delimiter) + segment;
                        }
                        continue;
                    }
                    segment = encodeURIComponent(value);
                    if (!matches[i].test(segment)) {
                        throw new TypeError('Expected "' + token.name + '" to match "' + token.pattern + '", but received "' + segment + '"');
                    }
                    path += token.prefix + segment;
                }
                return path;
            };
        }
        /**
         * Escape a regular expression string.
         *
         * @param  {String} str
         * @return {String}
         */
        function escapeString(str) {
            return str.replace(/([.+*?=^!:${}()[\]|\/])/g, '\\$1');
        }
        /**
         * Escape the capturing group by escaping special characters and meaning.
         *
         * @param  {String} group
         * @return {String}
         */
        function escapeGroup(group) {
            return group.replace(/([=!:$\/()])/g, '\\$1');
        }
        /**
         * Attach the keys as a property of the regexp.
         *
         * @param  {RegExp} re
         * @param  {Array}  keys
         * @return {RegExp}
         */
        function attachKeys(re, keys) {
            re.keys = keys;
            return re;
        }
        /**
         * Get the flags for a regexp from the options.
         *
         * @param  {Object} options
         * @return {String}
         */
        function flags(options) {
            return options.sensitive ? '' : 'i';
        }
        /**
         * Pull out keys from a regexp.
         *
         * @param  {RegExp} path
         * @param  {Array}  keys
         * @return {RegExp}
         */
        function regexpToRegexp(path, keys) {
            // Use a negative lookahead to match only capturing groups.
            var groups = path.source.match(/\((?!\?)/g);
            if (groups) {
                for (var i = 0; i < groups.length; i++) {
                    keys.push({
                        name: i,
                        prefix: null,
                        delimiter: null,
                        optional: false,
                        repeat: false,
                        pattern: null
                    });
                }
            }
            return attachKeys(path, keys);
        }
        /**
         * Transform an array into a regexp.
         *
         * @param  {Array}  path
         * @param  {Array}  keys
         * @param  {Object} options
         * @return {RegExp}
         */
        function arrayToRegexp(path, keys, options) {
            var parts = [];
            for (var i = 0; i < path.length; i++) {
                parts.push(pathToRegexp(path[i], keys, options).source);
            }
            var regexp = new RegExp('(?:' + parts.join('|') + ')', flags(options));
            return attachKeys(regexp, keys);
        }
        /**
         * Create a path regexp from string input.
         *
         * @param  {String} path
         * @param  {Array}  keys
         * @param  {Object} options
         * @return {RegExp}
         */
        function stringToRegexp(path, keys, options) {
            var tokens = parse(path);
            var re = tokensToRegExp(tokens, options);
            // Attach keys back to the regexp.
            for (var i = 0; i < tokens.length; i++) {
                if (typeof tokens[i] !== 'string') {
                    keys.push(tokens[i]);
                }
            }
            return attachKeys(re, keys);
        }
        /**
         * Expose a function for taking tokens and returning a RegExp.
         *
         * @param  {Array}  tokens
         * @param  {Array}  keys
         * @param  {Object} options
         * @return {RegExp}
         */
        function tokensToRegExp(tokens, options) {
            options = options || {};
            var strict = options.strict;
            var end = options.end !== false;
            var route = '';
            var lastToken = tokens[tokens.length - 1];
            var endsWithSlash = typeof lastToken === 'string' && /\/$/.test(lastToken);
            // Iterate over the tokens and create our regexp string.
            for (var i = 0; i < tokens.length; i++) {
                var token = tokens[i];
                if (typeof token === 'string') {
                    route += escapeString(token);
                }
                else {
                    var prefix = escapeString(token.prefix);
                    var capture = token.pattern;
                    if (token.repeat) {
                        capture += '(?:' + prefix + capture + ')*';
                    }
                    if (token.optional) {
                        if (prefix) {
                            capture = '(?:' + prefix + '(' + capture + '))?';
                        }
                        else {
                            capture = '(' + capture + ')?';
                        }
                    }
                    else {
                        capture = prefix + '(' + capture + ')';
                    }
                    route += capture;
                }
            }
            // In non-strict mode we allow a slash at the end of match. If the path to
            // match already ends with a slash, we remove it for consistency. The slash
            // is valid at the end of a path match, not in the middle. This is important
            // in non-ending mode, where "/test/" shouldn't match "/test//route".
            if (!strict) {
                route = (endsWithSlash ? route.slice(0, -2) : route) + '(?:\\/(?=$))?';
            }
            if (end) {
                route += '$';
            }
            else {
                // In non-ending mode, we need the capturing groups to match as much as
                // possible by using a positive lookahead to the end or next path segment.
                route += strict && endsWithSlash ? '' : '(?=\\/|$)';
            }
            return new RegExp('^' + route, flags(options));
        }
        /**
         * Normalize the given path string, returning a regular expression.
         *
         * An empty array can be passed in for the keys, which will hold the
         * placeholder key descriptions. For example, using `/user/:id`, `keys` will
         * contain `[{ name: 'id', delimiter: '/', optional: false, repeat: false }]`.
         *
         * @param  {(String|RegExp|Array)} path
         * @param  {Array}                 [keys]
         * @param  {Object}                [options]
         * @return {RegExp}
         */
        function pathToRegexp(path, keys, options) {
            keys = keys || [];
            if (!isarray(keys)) {
                options = keys;
                keys = [];
            }
            else if (!options) {
                options = {};
            }
            if (path instanceof RegExp) {
                return regexpToRegexp(path, keys);
            }
            if (isarray(path)) {
                return arrayToRegexp(path, keys, options);
            }
            return stringToRegexp(path, keys, options);
        }
        pathToRegexp_1.parse = parse_1;
        pathToRegexp_1.compile = compile_1;
        pathToRegexp_1.tokensToFunction = tokensToFunction_1;
        pathToRegexp_1.tokensToRegExp = tokensToRegExp_1;
        /**
           * Module dependencies.
           */
        /**
         * Short-cuts for global-object checks
         */
        var hasDocument = ('undefined' !== typeof document);
        var hasWindow = ('undefined' !== typeof window);
        var hasHistory = ('undefined' !== typeof history);
        var hasProcess = typeof process !== 'undefined';
        /**
         * Detect click event
         */
        var clickEvent = hasDocument && document.ontouchstart ? 'touchstart' : 'click';
        /**
         * To work properly with the URL
         * history.location generated polyfill in https://github.com/devote/HTML5-History-API
         */
        var isLocation = hasWindow && !!(window.history.location || window.location);
        /**
         * The page instance
         * @api private
         */
        function Page(options) {
            // public things
            this.callbacks = [];
            this.exits = [];
            this.current = '';
            this.len = 0;
            // private things
            this._dispatch = true;
            this._decodeURLComponents = true;
            this._base = '';
            this._strict = false;
            this._running = false;
            this._hashbang = false;
            // bound functions
            this._onclick = this._onclick.bind(this);
            this._onpopstate = this._onpopstate.bind(this);
            this.configure(options);
        }
        /**
         * Configure the instance of page. This can be called multiple times.
         *
         * @param {Object} options
         * @api public
         */
        Page.prototype.configure = function (options) {
            var opts = options || {};
            this._window = opts.window || (hasWindow && window);
            this._dispatch = opts.dispatch !== false;
            this._decodeURLComponents = opts.decodeURLComponents !== false;
            this._popstate = opts.popstate !== false && hasWindow;
            this._click = opts.click !== false && hasDocument;
            this._hashbang = !!opts.hashbang;
            var _window = this._window;
            if (this._popstate) {
                _window.addEventListener('popstate', this._onpopstate, false);
            }
            else if (hasWindow) {
                _window.removeEventListener('popstate', this._onpopstate, false);
            }
            if (this._click) {
                _window.document.addEventListener(clickEvent, this._onclick, false);
            }
            else if (hasDocument) {
                _window.document.removeEventListener(clickEvent, this._onclick, false);
            }
            if (this._hashbang && hasWindow && !hasHistory) {
                _window.addEventListener('hashchange', this._onpopstate, false);
            }
            else if (hasWindow) {
                _window.removeEventListener('hashchange', this._onpopstate, false);
            }
        };
        /**
         * Get or set basepath to `path`.
         *
         * @param {string} path
         * @api public
         */
        Page.prototype.base = function (path) {
            if (0 === arguments.length)
                return this._base;
            this._base = path;
        };
        /**
         * Gets the `base`, which depends on whether we are using History or
         * hashbang routing.
      
         * @api private
         */
        Page.prototype._getBase = function () {
            var base = this._base;
            if (!!base)
                return base;
            var loc = hasWindow && this._window && this._window.location;
            return (hasWindow && this._hashbang && loc && loc.protocol === 'file:') ? loc.pathname : base;
        };
        /**
         * Get or set strict path matching to `enable`
         *
         * @param {boolean} enable
         * @api public
         */
        Page.prototype.strict = function (enable) {
            if (0 === arguments.length)
                return this._strict;
            this._strict = enable;
        };
        /**
         * Bind with the given `options`.
         *
         * Options:
         *
         *    - `click` bind to click events [true]
         *    - `popstate` bind to popstate [true]
         *    - `dispatch` perform initial dispatch [true]
         *
         * @param {Object} options
         * @api public
         */
        Page.prototype.start = function (options) {
            this.configure(options);
            if (!this._dispatch)
                return;
            this._running = true;
            var url;
            if (isLocation) {
                var window = this._window;
                var loc = window.location;
                if (this._hashbang && ~loc.hash.indexOf('#!')) {
                    url = loc.hash.substr(2) + loc.search;
                }
                else if (this._hashbang) {
                    url = loc.search + loc.hash;
                }
                else {
                    url = loc.pathname + loc.search + loc.hash;
                }
            }
            this.replace(url, null, true, this._dispatch);
        };
        /**
         * Unbind click and popstate event handlers.
         *
         * @api public
         */
        Page.prototype.stop = function () {
            if (!this._running)
                return;
            this.current = '';
            this.len = 0;
            this._running = false;
            var window = this._window;
            hasDocument && window.document.removeEventListener(clickEvent, this._onclick, false);
            hasWindow && window.removeEventListener('popstate', this._onpopstate, false);
            hasWindow && window.removeEventListener('hashchange', this._onpopstate, false);
        };
        /**
         * Show `path` with optional `state` object.
         *
         * @param {string} path
         * @param {Object=} state
         * @param {boolean=} dispatch
         * @param {boolean=} push
         * @return {!Context}
         * @api public
         */
        Page.prototype.show = function (path, state, dispatch, push) {
            var ctx = new Context(path, state, this), prev = this.prevContext;
            this.prevContext = ctx;
            this.current = ctx.path;
            if (this._dispatch)
                this.dispatch(ctx, prev);
            if (false !== ctx.handled && false !== push)
                ctx.pushState();
            return ctx;
        };
        /**
         * Goes back in the history
         * Back should always let the current route push state and then go back.
         *
         * @param {string} path - fallback path to go back if no more history exists, if undefined defaults to page.base
         * @param {Object=} state
         * @api public
         */
        Page.prototype.back = function (path, state) {
            var page = this;
            if (this.len > 0) {
                var window = this._window;
                // this may need more testing to see if all browsers
                // wait for the next tick to go back in history
                hasHistory && window.history.back();
                this.len--;
            }
            else if (path) {
                setTimeout(function () {
                    page.show(path, state);
                });
            }
            else {
                setTimeout(function () {
                    page.show(page._getBase(), state);
                });
            }
        };
        /**
         * Register route to redirect from one path to other
         * or just redirect to another route
         *
         * @param {string} from - if param 'to' is undefined redirects to 'from'
         * @param {string=} to
         * @api public
         */
        Page.prototype.redirect = function (from, to) {
            var inst = this;
            // Define route from a path to another
            if ('string' === typeof from && 'string' === typeof to) {
                page.call(this, from, function (e) {
                    setTimeout(function () {
                        inst.replace(/** @type {!string} */ (to));
                    }, 0);
                });
            }
            // Wait for the push state and replace it with another
            if ('string' === typeof from && 'undefined' === typeof to) {
                setTimeout(function () {
                    inst.replace(from);
                }, 0);
            }
        };
        /**
         * Replace `path` with optional `state` object.
         *
         * @param {string} path
         * @param {Object=} state
         * @param {boolean=} init
         * @param {boolean=} dispatch
         * @return {!Context}
         * @api public
         */
        Page.prototype.replace = function (path, state, init, dispatch) {
            var ctx = new Context(path, state, this), prev = this.prevContext;
            this.prevContext = ctx;
            this.current = ctx.path;
            ctx.init = init;
            ctx.save(); // save before dispatching, which may redirect
            if (false !== dispatch)
                this.dispatch(ctx, prev);
            return ctx;
        };
        /**
         * Dispatch the given `ctx`.
         *
         * @param {Context} ctx
         * @api private
         */
        Page.prototype.dispatch = function (ctx, prev) {
            var i = 0, j = 0, page = this;
            function nextExit() {
                var fn = page.exits[j++];
                if (!fn)
                    return nextEnter();
                fn(prev, nextExit);
            }
            function nextEnter() {
                var fn = page.callbacks[i++];
                if (ctx.path !== page.current) {
                    ctx.handled = false;
                    return;
                }
                if (!fn)
                    return unhandled.call(page, ctx);
                fn(ctx, nextEnter);
            }
            if (prev) {
                nextExit();
            }
            else {
                nextEnter();
            }
        };
        /**
         * Register an exit route on `path` with
         * callback `fn()`, which will be called
         * on the previous context when a new
         * page is visited.
         */
        Page.prototype.exit = function (path, fn) {
            if (typeof path === 'function') {
                return this.exit('*', path);
            }
            var route = new Route(path, null, this);
            for (var i = 1; i < arguments.length; ++i) {
                this.exits.push(route.middleware(arguments[i]));
            }
        };
        /**
         * Handle "click" events.
         */
        /* jshint +W054 */
        Page.prototype._onclick = function (e) {
            if (1 !== this._which(e))
                return;
            if (e.metaKey || e.ctrlKey || e.shiftKey)
                return;
            if (e.defaultPrevented)
                return;
            // ensure link
            // use shadow dom when available if not, fall back to composedPath()
            // for browsers that only have shady
            var el = e.target;
            var eventPath = e.path || (e.composedPath ? e.composedPath() : null);
            if (eventPath) {
                for (var i = 0; i < eventPath.length; i++) {
                    if (!eventPath[i].nodeName)
                        continue;
                    if (eventPath[i].nodeName.toUpperCase() !== 'A')
                        continue;
                    if (!eventPath[i].href)
                        continue;
                    el = eventPath[i];
                    break;
                }
            }
            // continue ensure link
            // el.nodeName for svg links are 'a' instead of 'A'
            while (el && 'A' !== el.nodeName.toUpperCase())
                el = el.parentNode;
            if (!el || 'A' !== el.nodeName.toUpperCase())
                return;
            // check if link is inside an svg
            // in this case, both href and target are always inside an object
            var svg = (typeof el.href === 'object') && el.href.constructor.name === 'SVGAnimatedString';
            // Ignore if tag has
            // 1. "download" attribute
            // 2. rel="external" attribute
            if (el.hasAttribute('download') || el.getAttribute('rel') === 'external')
                return;
            // ensure non-hash for the same path
            var link = el.getAttribute('href');
            if (!this._hashbang && this._samePath(el) && (el.hash || '#' === link))
                return;
            // Check for mailto: in the href
            if (link && link.indexOf('mailto:') > -1)
                return;
            // check target
            // svg target is an object and its desired value is in .baseVal property
            if (svg ? el.target.baseVal : el.target)
                return;
            // x-origin
            // note: svg links that are not relative don't call click events (and skip page.js)
            // consequently, all svg links tested inside page.js are relative and in the same origin
            if (!svg && !this.sameOrigin(el.href))
                return;
            // rebuild path
            // There aren't .pathname and .search properties in svg links, so we use href
            // Also, svg href is an object and its desired value is in .baseVal property
            var path = svg ? el.href.baseVal : (el.pathname + el.search + (el.hash || ''));
            path = path[0] !== '/' ? '/' + path : path;
            // strip leading "/[drive letter]:" on NW.js on Windows
            if (hasProcess && path.match(/^\/[a-zA-Z]:\//)) {
                path = path.replace(/^\/[a-zA-Z]:\//, '/');
            }
            // same page
            var orig = path;
            var pageBase = this._getBase();
            if (path.indexOf(pageBase) === 0) {
                path = path.substr(pageBase.length);
            }
            if (this._hashbang)
                path = path.replace('#!', '');
            if (pageBase && orig === path)
                return;
            e.preventDefault();
            this.show(orig);
        };
        /**
         * Handle "populate" events.
         * @api private
         */
        Page.prototype._onpopstate = (function () {
            var loaded = false;
            if (!hasWindow) {
                return;
            }
            if (hasDocument && document.readyState === 'complete') {
                loaded = true;
            }
            else {
                window.addEventListener('load', function () {
                    setTimeout(function () {
                        loaded = true;
                    }, 0);
                });
            }
            return function onpopstate(e) {
                if (!loaded)
                    return;
                var page = this;
                if (e.state) {
                    var path = e.state.path;
                    page.replace(path, e.state);
                }
                else if (isLocation) {
                    var loc = page._window.location;
                    page.show(loc.pathname + loc.search + loc.hash, undefined, undefined, false);
                }
            };
        })();
        /**
         * Event button.
         */
        Page.prototype._which = function (e) {
            e = e || (hasWindow && this._window.event);
            return null == e.which ? e.button : e.which;
        };
        /**
         * Convert to a URL object
         * @api private
         */
        Page.prototype._toURL = function (href) {
            var window = this._window;
            if (typeof URL === 'function' && isLocation) {
                return new URL(href, window.location.toString());
            }
            else if (hasDocument) {
                var anc = window.document.createElement('a');
                anc.href = href;
                return anc;
            }
        };
        /**
         * Check if `href` is the same origin.
         * @param {string} href
         * @api public
         */
        Page.prototype.sameOrigin = function (href) {
            if (!href || !isLocation)
                return false;
            var url = this._toURL(href);
            var window = this._window;
            var loc = window.location;
            return loc.protocol === url.protocol &&
                loc.hostname === url.hostname &&
                loc.port === url.port;
        };
        /**
         * @api private
         */
        Page.prototype._samePath = function (url) {
            if (!isLocation)
                return false;
            var window = this._window;
            var loc = window.location;
            return url.pathname === loc.pathname &&
                url.search === loc.search;
        };
        /**
         * Remove URL encoding from the given `str`.
         * Accommodates whitespace in both x-www-form-urlencoded
         * and regular percent-encoded form.
         *
         * @param {string} val - URL component to decode
         * @api private
         */
        Page.prototype._decodeURLEncodedURIComponent = function (val) {
            if (typeof val !== 'string') {
                return val;
            }
            return this._decodeURLComponents ? decodeURIComponent(val.replace(/\+/g, ' ')) : val;
        };
        /**
         * Create a new `page` instance and function
         */
        function createPage(options) {
            var pageInstance = new Page();
            function pageFn( /* args */) {
                return page.apply(pageInstance, arguments);
            }
            // Copy all of the things over. In 2.0 maybe we use setPrototypeOf
            pageFn.callbacks = pageInstance.callbacks;
            pageFn.exits = pageInstance.exits;
            pageFn.base = pageInstance.base.bind(pageInstance);
            pageFn.strict = pageInstance.strict.bind(pageInstance);
            pageFn.start = pageInstance.start.bind(pageInstance);
            pageFn.stop = pageInstance.stop.bind(pageInstance);
            pageFn.show = pageInstance.show.bind(pageInstance);
            pageFn.back = pageInstance.back.bind(pageInstance);
            pageFn.redirect = pageInstance.redirect.bind(pageInstance);
            pageFn.replace = pageInstance.replace.bind(pageInstance);
            pageFn.dispatch = pageInstance.dispatch.bind(pageInstance);
            pageFn.exit = pageInstance.exit.bind(pageInstance);
            pageFn.configure = pageInstance.configure.bind(pageInstance);
            pageFn.sameOrigin = pageInstance.sameOrigin.bind(pageInstance);
            pageFn.create = createPage;
            Object.defineProperty(pageFn, 'len', {
                get: function () {
                    return pageInstance.len;
                },
                set: function (val) {
                    pageInstance.len = val;
                }
            });
            Object.defineProperty(pageFn, 'current', {
                get: function () {
                    return pageInstance.current;
                },
                set: function (val) {
                    pageInstance.current = val;
                }
            });
            // In 2.0 these can be named exports
            pageFn.Context = Context;
            pageFn.Route = Route;
            return pageFn;
        }
        /**
         * Register `path` with callback `fn()`,
         * or route `path`, or redirection,
         * or `page.start()`.
         *
         *   page(fn);
         *   page('*', fn);
         *   page('/user/:id', load, user);
         *   page('/user/' + user.id, { some: 'thing' });
         *   page('/user/' + user.id);
         *   page('/from', '/to')
         *   page();
         *
         * @param {string|!Function|!Object} path
         * @param {Function=} fn
         * @api public
         */
        function page(path, fn) {
            // <callback>
            if ('function' === typeof path) {
                return page.call(this, '*', path);
            }
            // route <path> to <callback ...>
            if ('function' === typeof fn) {
                var route = new Route(/** @type {string} */ (path), null, this);
                for (var i = 1; i < arguments.length; ++i) {
                    this.callbacks.push(route.middleware(arguments[i]));
                }
                // show <path> with [state]
            }
            else if ('string' === typeof path) {
                this['string' === typeof fn ? 'redirect' : 'show'](path, fn);
                // start [options]
            }
            else {
                this.start(path);
            }
        }
        /**
         * Unhandled `ctx`. When it's not the initial
         * popstate then redirect. If you wish to handle
         * 404s on your own use `page('*', callback)`.
         *
         * @param {Context} ctx
         * @api private
         */
        function unhandled(ctx) {
            if (ctx.handled)
                return;
            var current;
            var page = this;
            var window = page._window;
            if (page._hashbang) {
                current = isLocation && this._getBase() + window.location.hash.replace('#!', '');
            }
            else {
                current = isLocation && window.location.pathname + window.location.search;
            }
            if (current === ctx.canonicalPath)
                return;
            page.stop();
            ctx.handled = false;
            isLocation && (window.location.href = ctx.canonicalPath);
        }
        /**
         * Initialize a new "request" `Context`
         * with the given `path` and optional initial `state`.
         *
         * @constructor
         * @param {string} path
         * @param {Object=} state
         * @api public
         */
        function Context(path, state, pageInstance) {
            var _page = this.page = pageInstance || page;
            var window = _page._window;
            var hashbang = _page.hashbang;
            var pageBase = _page._getBase();
            if ('/' === path[0] && 0 !== path.indexOf(pageBase))
                path = pageBase + (hashbang ? '#!' : '') + path;
            var i = path.indexOf('?');
            this.canonicalPath = path;
            this.path = path.replace(pageBase, '') || '/';
            if (hashbang)
                this.path = this.path.replace('#!', '') || '/';
            this.title = (hasDocument && window.document.title);
            this.state = state || {};
            this.state.path = path;
            this.querystring = ~i ? _page._decodeURLEncodedURIComponent(path.slice(i + 1)) : '';
            this.pathname = _page._decodeURLEncodedURIComponent(~i ? path.slice(0, i) : path);
            this.params = {};
            // fragment
            this.hash = '';
            if (!hashbang) {
                if (!~this.path.indexOf('#'))
                    return;
                var parts = this.path.split('#');
                this.path = this.pathname = parts[0];
                this.hash = _page._decodeURLEncodedURIComponent(parts[1]) || '';
                this.querystring = this.querystring.split('#')[0];
            }
        }
        /**
         * Push state.
         *
         * @api private
         */
        Context.prototype.pushState = function () {
            var page = this.page;
            var window = page._window;
            var hashbang = page._hashbang;
            page.len++;
            if (hasHistory) {
                window.history.pushState(this.state, this.title, hashbang && this.path !== '/' ? '#!' + this.path : this.canonicalPath);
            }
        };
        /**
         * Save the context state.
         *
         * @api public
         */
        Context.prototype.save = function () {
            var page = this.page;
            if (hasHistory && page._window.location.protocol !== 'file:') {
                page._window.history.replaceState(this.state, this.title, page._hashbang && this.path !== '/' ? '#!' + this.path : this.canonicalPath);
            }
        };
        /**
         * Initialize `Route` with the given HTTP `path`,
         * and an array of `callbacks` and `options`.
         *
         * Options:
         *
         *   - `sensitive`    enable case-sensitive routes
         *   - `strict`       enable strict matching for trailing slashes
         *
         * @constructor
         * @param {string} path
         * @param {Object=} options
         * @api private
         */
        function Route(path, options, page) {
            var _page = this.page = page || globalPage;
            var opts = options || {};
            opts.strict = opts.strict || page._strict;
            this.path = (path === '*') ? '(.*)' : path;
            this.method = 'GET';
            this.regexp = pathToRegexp_1(this.path, this.keys = [], opts);
        }
        /**
         * Return route middleware with
         * the given callback `fn()`.
         *
         * @param {Function} fn
         * @return {Function}
         * @api public
         */
        Route.prototype.middleware = function (fn) {
            var self = this;
            return function (ctx, next) {
                if (self.match(ctx.path, ctx.params))
                    return fn(ctx, next);
                next();
            };
        };
        /**
         * Check if this route matches `path`, if so
         * populate `params`.
         *
         * @param {string} path
         * @param {Object} params
         * @return {boolean}
         * @api private
         */
        Route.prototype.match = function (path, params) {
            var keys = this.keys, qsIndex = path.indexOf('?'), pathname = ~qsIndex ? path.slice(0, qsIndex) : path, m = this.regexp.exec(decodeURIComponent(pathname));
            if (!m)
                return false;
            for (var i = 1, len = m.length; i < len; ++i) {
                var key = keys[i - 1];
                var val = this.page._decodeURLEncodedURIComponent(m[i]);
                if (val !== undefined || !(hasOwnProperty.call(params, key.name))) {
                    params[key.name] = val;
                }
            }
            return true;
        };
        /**
         * Module exports.
         */
        var globalPage = createPage();
        var page_js = globalPage;
        page.default = globalPage;
        return page_js;
    })));
});
var Router = /** @class */ (function () {
    function Router(hostRef) {
        registerInstance(this, hostRef);
        this._url = '/';
        this.routes = [];
        this.hash = ''; //  '#';
        this.changed = createEvent(this, "changed", 7);
    }
    Router.prototype.componentDidLoad = function () {
        this.el.style.display = "none";
        this.postRender();
        // init the landing page
        if (this.level == 0) {
            page(window.location.pathname);
        }
    };
    Router.prototype.componentDidUpdate = function () {
        this.postRender();
    };
    Router.prototype.postRender = function () {
        var _this = this;
        var routeComponents = Array.from(this.el.getElementsByTagName('ema-route'));
        routeComponents.forEach(function (route) {
            _this.routes.push({
                'component': route.component,
                'component-props': route.componentProps,
                'url': route.url,
                'exact': route.exact,
                'action': route.action,
                'action-params': route.actionParams,
            });
        });
        this.routes.forEach(function (route) {
            // Defines a route mapping path to the given callback(s). Each callback is invoked with two arguments, context and next. Much like Express invoking next will call the next registered callback with the given path.
            // Under certain conditions, links will be disregarded and will not be dispatched, such as:
            // Links that are not of the same origin
            // Links with the download attribute
            // Links with the target attribute
            // Links with the rel="external" attribute
            page(route.url, function (pageContext) {
                if (route.component) {
                    pageContext.state.component = route.component;
                }
                _this._pageContext = pageContext;
                _this.state = {
                    context: pageContext,
                    route: route,
                    routes: _this.routes,
                    component: route.component,
                };
                _this.activateRoute();
                _this.changed.emit(_this.state);
            });
            // page('/', user.list)
            // page('/user/:id/edit', user.load, user.edit)
            // page('*', notfound)
        });
    };
    Router.prototype.activateRoute = function () {
        var _this = this;
        var breadcrumb = [];
        var component;
        var pageClass = 'page';
        var pageContext = this.state.context;
        var route = this.state.route;
        var routeComponent;
        var url = this._url = pageContext.state.path;
        var urlParsed = this.urlParamsToUrl(route.url);
        if (!route.component) {
            console.error('No component defined for url: ' + url);
            return;
        }
        else {
            component = route.component;
        }
        this.deleteRouterClasses();
        pageContext.state.path.split('/').forEach(function (p) {
            if (p !== '') {
                breadcrumb.push(p);
            }
        });
        if (pageContext.state.component) {
            routeComponent = pageContext.state.component;
        }
        breadcrumb.forEach(function (level) {
            pageClass += ('-' + level);
            _this.removeClass(document.querySelector('body'), pageClass);
        });
        // todo: fixme:
        if (component && component === routeComponent && url === urlParsed) {
            // remove the previous component
            if (this._compDiv) {
                if (this.targetSelector) {
                    if (document.querySelector(this.targetSelector)) {
                        document.querySelector(this.targetSelector).removeChild(this._compDiv);
                    }
                }
                else {
                    this.el.parentNode.removeChild(this._compDiv);
                }
            }
            // initializa the current component
            this._compDiv = document.createElement(component);
            // set the component props
            if (route['component-props']) {
                // pass props to the component
                var cprops_1 = JSON.parse(route['component-props']);
                Object.keys(cprops_1).forEach(function (k) {
                    var v = cprops_1[k];
                    if (typeof v !== 'string') {
                        v = JSON.stringify(v);
                    }
                    _this._compDiv.setAttribute(k, v);
                });
            }
            // render component
            if (this.targetSelector) {
                if (document.querySelector(this.targetSelector)) {
                    document.querySelector(this.targetSelector).appendChild(this._compDiv);
                }
            }
            else {
                this.el.parentNode.insertBefore(this._compDiv, this.el.nextSibling);
            }
            // add route classes to body tag
            this.addClass(document.querySelector('body'), component);
        }
        this.addClass(document.querySelector('body'), pageClass);
    };
    Router.prototype.deleteRouterClasses = function () {
        var _this = this;
        // remove body classes
        var bodyElement = document.querySelector('body');
        this.state.routes.forEach(function (r) {
            if (r.component) {
                _this.removeClass(bodyElement, r.component);
            }
        });
        bodyElement.classList.forEach(function (classId) {
            if (classId.startsWith('page-')) {
                _this.removeClass(bodyElement, classId);
            }
        });
    };
    Router.prototype.urlParamsToUrl = function (url) {
        var parsedUrl = url;
        var params = this.state.context.params;
        var parts = url.split('/');
        var hasParams = false;
        parts.forEach(function (part, i) {
            var variable;
            var value;
            if (part.startsWith(':')) {
                hasParams = true;
                variable = part.split(':')[1];
                value = params[variable];
                parsedUrl = parsedUrl.replace(part, value);
            }
        });
        if (hasParams) {
            return parsedUrl;
        }
        else {
            return url;
        }
    };
    Router.prototype.url = function (url) {
        return __awaiter(this, void 0, void 0, function () {
            return __generator(this, function (_a) {
                if (url) {
                    page(this.hash + url);
                }
                else {
                    return [2 /*return*/, this._url];
                }
                return [2 /*return*/];
            });
        });
    };
    Router.prototype.page = function () {
        return __awaiter(this, void 0, void 0, function () {
            return __generator(this, function (_a) {
                return [2 /*return*/, page];
            });
        });
    };
    Router.prototype.getState = function () {
        return __awaiter(this, void 0, void 0, function () {
            return __generator(this, function (_a) {
                return [2 /*return*/, this.state];
            });
        });
    };
    Router.prototype.addClass = function (el, className) {
        if (el.classList)
            el.classList.add(className);
        else
            el.className += ' ' + className;
    };
    Router.prototype.removeClass = function (el, className) {
        if (el.classList)
            el.classList.remove(className);
        else
            el.className = el.className.replace(new RegExp('(^|\\b)' + className.split(' ').join('|') + '(\\b|$)', 'gi'), ' ');
    };
    Router.prototype.render = function () {
        return (h("div", null));
    };
    Object.defineProperty(Router.prototype, "el", {
        get: function () { return getElement(this); },
        enumerable: true,
        configurable: true
    });
    return Router;
}());
export { Router as ema_router };
