UNPKG

30.1 kBJavaScriptView Raw
1(function (global, factory) {
2 typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
3 typeof define === 'function' && define.amd ? define(['exports'], factory) :
4 (global = global || self, factory(global.Curi = {}));
5}(this, function (exports) { 'use strict';
6
7 function pathname(route, params) {
8 return route.methods.pathname(params);
9 }
10
11 function isAsyncRoute(route) {
12 return typeof route.methods.resolve !== "undefined";
13 }
14 function isExternalRedirect(redirect) {
15 return "externalURL" in redirect;
16 }
17 function isRedirectLocation(redirect) {
18 return "url" in redirect;
19 }
20
21 function finishResponse(route, match, resolvedResults, router, external) {
22 var _a = resolvedResults || {}, _b = _a.resolved, resolved = _b === void 0 ? null : _b, _c = _a.error, error = _c === void 0 ? null : _c;
23 var response = {
24 data: undefined,
25 body: undefined,
26 meta: undefined
27 };
28 for (var key in match) {
29 response[key] = match[key];
30 }
31 if (!route.methods.respond) {
32 return response;
33 }
34 var results = route.methods.respond({
35 resolved: resolved,
36 error: error,
37 match: match,
38 external: external
39 });
40 if (!results) {
41 {
42 console.warn("\"" + match.name + "\"'s response function did not return anything. Did you forget to include a return statement?");
43 }
44 return response;
45 }
46 {
47 var validProperties_1 = {
48 meta: true,
49 body: true,
50 data: true,
51 redirect: true
52 };
53 Object.keys(results).forEach(function (property) {
54 if (!validProperties_1.hasOwnProperty(property)) {
55 console.warn("\"" + property + "\" is not a valid response property. The valid properties are:\n\n " + Object.keys(validProperties_1).join(", "));
56 }
57 });
58 }
59 response["meta"] = results["meta"];
60 response["body"] = results["body"];
61 response["data"] = results["data"];
62 if (results["redirect"]) {
63 response["redirect"] = createRedirect(results["redirect"], router);
64 }
65 return response;
66 }
67 function createRedirect(redirect, router) {
68 if (isExternalRedirect(redirect)) {
69 return redirect;
70 }
71 var name = redirect.name, params = redirect.params, query = redirect.query, hash = redirect.hash, state = redirect.state;
72 var url = isRedirectLocation(redirect)
73 ? redirect.url
74 : router.url({ name: name, params: params, query: query, hash: hash });
75 return {
76 name: name,
77 params: params,
78 query: query,
79 hash: hash,
80 state: state,
81 url: url
82 };
83 }
84
85 function createRouter(historyConstructor, routes, options) {
86 if (options === void 0) { options = {}; }
87 var latestResponse;
88 var latestNavigation;
89 var history = historyConstructor(function (pendingNav) {
90 var navigation = {
91 action: pendingNav.action,
92 previous: latestResponse
93 };
94 var matched = routes.match(pendingNav.location);
95 if (!matched) {
96 {
97 console.warn("The current location (" + pendingNav.location.pathname + ") has no matching route, " +
98 'so a response could not be emitted. A catch-all route ({ path: "(.*)" }) ' +
99 "can be used to match locations with no other matching route.");
100 }
101 pendingNav.finish();
102 finishAndResetNavCallbacks();
103 return;
104 }
105 var route = matched.route, match = matched.match;
106 if (!isAsyncRoute(route)) {
107 finalizeResponseAndEmit(route, match, pendingNav, navigation, null);
108 }
109 else {
110 announceAsyncNav();
111 route.methods
112 .resolve(match, options.external)
113 .then(function (resolved) { return ({ resolved: resolved, error: null }); }, function (error) { return ({ error: error, resolved: null }); })
114 .then(function (resolved) {
115 if (pendingNav.cancelled) {
116 return;
117 }
118 finalizeResponseAndEmit(route, match, pendingNav, navigation, resolved);
119 });
120 }
121 }, options.history || {});
122 function finalizeResponseAndEmit(route, match, pending, navigation, resolved) {
123 asyncNavComplete();
124 pending.finish();
125 var response = finishResponse(route, match, resolved, router, options.external);
126 finishAndResetNavCallbacks();
127 emitImmediate(response, navigation);
128 }
129 var _a = options.invisibleRedirects, invisibleRedirects = _a === void 0 ? false : _a;
130 function emitImmediate(response, navigation) {
131 if (!response.redirect ||
132 !invisibleRedirects ||
133 isExternalRedirect(response.redirect)) {
134 latestResponse = response;
135 latestNavigation = navigation;
136 var emit = { response: response, navigation: navigation, router: router };
137 callObservers(emit);
138 callOneTimersAndSideEffects(emit);
139 }
140 if (response.redirect !== undefined &&
141 !isExternalRedirect(response.redirect)) {
142 history.navigate(response.redirect, "replace");
143 }
144 }
145 function callObservers(emitted) {
146 observers.forEach(function (fn) {
147 fn(emitted);
148 });
149 }
150 function callOneTimersAndSideEffects(emitted) {
151 oneTimers.splice(0).forEach(function (fn) {
152 fn(emitted);
153 });
154 if (options.sideEffects) {
155 options.sideEffects.forEach(function (fn) {
156 fn(emitted);
157 });
158 }
159 }
160 /* router.observer & router.once */
161 var observers = [];
162 var oneTimers = [];
163 function observe(fn, options) {
164 var _a = (options || {}).initial, initial = _a === void 0 ? true : _a;
165 observers.push(fn);
166 if (latestResponse && initial) {
167 fn({
168 response: latestResponse,
169 navigation: latestNavigation,
170 router: router
171 });
172 }
173 return function () {
174 observers = observers.filter(function (obs) {
175 return obs !== fn;
176 });
177 };
178 }
179 function once(fn, options) {
180 var _a = (options || {}).initial, initial = _a === void 0 ? true : _a;
181 if (latestResponse && initial) {
182 fn({
183 response: latestResponse,
184 navigation: latestNavigation,
185 router: router
186 });
187 }
188 else {
189 oneTimers.push(fn);
190 }
191 }
192 /* router.url */
193 function url(details) {
194 var name = details.name, params = details.params, hash = details.hash, query = details.query;
195 var pathname$1;
196 if (name) {
197 var route = router.route(name);
198 if (route) {
199 pathname$1 = pathname(route, params);
200 }
201 }
202 return history.url({ pathname: pathname$1, hash: hash, query: query });
203 }
204 /* router.navigate */
205 var cancelCallback;
206 var finishCallback;
207 function navigate(details) {
208 cancelAndResetNavCallbacks();
209 var url = details.url, state = details.state, method = details.method;
210 history.navigate({ url: url, state: state }, method);
211 if (details.cancelled || details.finished) {
212 cancelCallback = details.cancelled;
213 finishCallback = details.finished;
214 return resetCallbacks;
215 }
216 }
217 function cancelAndResetNavCallbacks() {
218 if (cancelCallback) {
219 cancelCallback();
220 }
221 resetCallbacks();
222 }
223 function finishAndResetNavCallbacks() {
224 if (finishCallback) {
225 finishCallback();
226 }
227 resetCallbacks();
228 }
229 function resetCallbacks() {
230 cancelCallback = undefined;
231 finishCallback = undefined;
232 }
233 /* router.cancel */
234 var cancelWith;
235 var asyncNavNotifiers = [];
236 function cancel(fn) {
237 asyncNavNotifiers.push(fn);
238 return function () {
239 asyncNavNotifiers = asyncNavNotifiers.filter(function (can) {
240 return can !== fn;
241 });
242 };
243 }
244 // let any async navigation listeners (observers from router.cancel)
245 // know that there is an asynchronous navigation happening
246 function announceAsyncNav() {
247 if (asyncNavNotifiers.length && cancelWith === undefined) {
248 cancelWith = function () {
249 history.cancel();
250 asyncNavComplete();
251 cancelAndResetNavCallbacks();
252 };
253 asyncNavNotifiers.forEach(function (fn) {
254 fn(cancelWith);
255 });
256 }
257 }
258 function asyncNavComplete() {
259 if (cancelWith) {
260 cancelWith = undefined;
261 asyncNavNotifiers.forEach(function (fn) {
262 fn();
263 });
264 }
265 }
266 var router = {
267 route: routes.route,
268 history: history,
269 external: options.external,
270 observe: observe,
271 once: once,
272 cancel: cancel,
273 url: url,
274 navigate: navigate,
275 current: function () {
276 return {
277 response: latestResponse,
278 navigation: latestNavigation
279 };
280 },
281 destroy: function () {
282 history.destroy();
283 }
284 };
285 history.current();
286 return router;
287 }
288
289 /**
290 * Expose `pathToRegexp`.
291 */
292 var pathToRegexp_1 = pathToRegexp;
293 var parse_1 = parse;
294 var compile_1 = compile;
295 var tokensToFunction_1 = tokensToFunction;
296 var tokensToRegExp_1 = tokensToRegExp;
297
298 /**
299 * Default configs.
300 */
301 var DEFAULT_DELIMITER = '/';
302 var DEFAULT_DELIMITERS = './';
303
304 /**
305 * The main path matching regexp utility.
306 *
307 * @type {RegExp}
308 */
309 var PATH_REGEXP = new RegExp([
310 // Match escaped characters that would otherwise appear in future matches.
311 // This allows the user to escape special characters that won't transform.
312 '(\\\\.)',
313 // Match Express-style parameters and un-named parameters with a prefix
314 // and optional suffixes. Matches appear as:
315 //
316 // ":test(\\d+)?" => ["test", "\d+", undefined, "?"]
317 // "(\\d+)" => [undefined, undefined, "\d+", undefined]
318 '(?:\\:(\\w+)(?:\\(((?:\\\\.|[^\\\\()])+)\\))?|\\(((?:\\\\.|[^\\\\()])+)\\))([+*?])?'
319 ].join('|'), 'g');
320
321 /**
322 * Parse a string for the raw tokens.
323 *
324 * @param {string} str
325 * @param {Object=} options
326 * @return {!Array}
327 */
328 function parse (str, options) {
329 var tokens = [];
330 var key = 0;
331 var index = 0;
332 var path = '';
333 var defaultDelimiter = (options && options.delimiter) || DEFAULT_DELIMITER;
334 var delimiters = (options && options.delimiters) || DEFAULT_DELIMITERS;
335 var pathEscaped = false;
336 var res;
337
338 while ((res = PATH_REGEXP.exec(str)) !== null) {
339 var m = res[0];
340 var escaped = res[1];
341 var offset = res.index;
342 path += str.slice(index, offset);
343 index = offset + m.length;
344
345 // Ignore already escaped sequences.
346 if (escaped) {
347 path += escaped[1];
348 pathEscaped = true;
349 continue
350 }
351
352 var prev = '';
353 var next = str[index];
354 var name = res[2];
355 var capture = res[3];
356 var group = res[4];
357 var modifier = res[5];
358
359 if (!pathEscaped && path.length) {
360 var k = path.length - 1;
361
362 if (delimiters.indexOf(path[k]) > -1) {
363 prev = path[k];
364 path = path.slice(0, k);
365 }
366 }
367
368 // Push the current path onto the tokens.
369 if (path) {
370 tokens.push(path);
371 path = '';
372 pathEscaped = false;
373 }
374
375 var partial = prev !== '' && next !== undefined && next !== prev;
376 var repeat = modifier === '+' || modifier === '*';
377 var optional = modifier === '?' || modifier === '*';
378 var delimiter = prev || defaultDelimiter;
379 var pattern = capture || group;
380
381 tokens.push({
382 name: name || key++,
383 prefix: prev,
384 delimiter: delimiter,
385 optional: optional,
386 repeat: repeat,
387 partial: partial,
388 pattern: pattern ? escapeGroup(pattern) : '[^' + escapeString(delimiter) + ']+?'
389 });
390 }
391
392 // Push any remaining characters.
393 if (path || index < str.length) {
394 tokens.push(path + str.substr(index));
395 }
396
397 return tokens
398 }
399
400 /**
401 * Compile a string to a template function for the path.
402 *
403 * @param {string} str
404 * @param {Object=} options
405 * @return {!function(Object=, Object=)}
406 */
407 function compile (str, options) {
408 return tokensToFunction(parse(str, options))
409 }
410
411 /**
412 * Expose a method for transforming tokens into the path function.
413 */
414 function tokensToFunction (tokens) {
415 // Compile all the tokens into regexps.
416 var matches = new Array(tokens.length);
417
418 // Compile all the patterns before compilation.
419 for (var i = 0; i < tokens.length; i++) {
420 if (typeof tokens[i] === 'object') {
421 matches[i] = new RegExp('^(?:' + tokens[i].pattern + ')$');
422 }
423 }
424
425 return function (data, options) {
426 var path = '';
427 var encode = (options && options.encode) || encodeURIComponent;
428
429 for (var i = 0; i < tokens.length; i++) {
430 var token = tokens[i];
431
432 if (typeof token === 'string') {
433 path += token;
434 continue
435 }
436
437 var value = data ? data[token.name] : undefined;
438 var segment;
439
440 if (Array.isArray(value)) {
441 if (!token.repeat) {
442 throw new TypeError('Expected "' + token.name + '" to not repeat, but got array')
443 }
444
445 if (value.length === 0) {
446 if (token.optional) continue
447
448 throw new TypeError('Expected "' + token.name + '" to not be empty')
449 }
450
451 for (var j = 0; j < value.length; j++) {
452 segment = encode(value[j], token);
453
454 if (!matches[i].test(segment)) {
455 throw new TypeError('Expected all "' + token.name + '" to match "' + token.pattern + '"')
456 }
457
458 path += (j === 0 ? token.prefix : token.delimiter) + segment;
459 }
460
461 continue
462 }
463
464 if (typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean') {
465 segment = encode(String(value), token);
466
467 if (!matches[i].test(segment)) {
468 throw new TypeError('Expected "' + token.name + '" to match "' + token.pattern + '", but got "' + segment + '"')
469 }
470
471 path += token.prefix + segment;
472 continue
473 }
474
475 if (token.optional) {
476 // Prepend partial segment prefixes.
477 if (token.partial) path += token.prefix;
478
479 continue
480 }
481
482 throw new TypeError('Expected "' + token.name + '" to be ' + (token.repeat ? 'an array' : 'a string'))
483 }
484
485 return path
486 }
487 }
488
489 /**
490 * Escape a regular expression string.
491 *
492 * @param {string} str
493 * @return {string}
494 */
495 function escapeString (str) {
496 return str.replace(/([.+*?=^!:${}()[\]|/\\])/g, '\\$1')
497 }
498
499 /**
500 * Escape the capturing group by escaping special characters and meaning.
501 *
502 * @param {string} group
503 * @return {string}
504 */
505 function escapeGroup (group) {
506 return group.replace(/([=!:$/()])/g, '\\$1')
507 }
508
509 /**
510 * Get the flags for a regexp from the options.
511 *
512 * @param {Object} options
513 * @return {string}
514 */
515 function flags (options) {
516 return options && options.sensitive ? '' : 'i'
517 }
518
519 /**
520 * Pull out keys from a regexp.
521 *
522 * @param {!RegExp} path
523 * @param {Array=} keys
524 * @return {!RegExp}
525 */
526 function regexpToRegexp (path, keys) {
527 if (!keys) return path
528
529 // Use a negative lookahead to match only capturing groups.
530 var groups = path.source.match(/\((?!\?)/g);
531
532 if (groups) {
533 for (var i = 0; i < groups.length; i++) {
534 keys.push({
535 name: i,
536 prefix: null,
537 delimiter: null,
538 optional: false,
539 repeat: false,
540 partial: false,
541 pattern: null
542 });
543 }
544 }
545
546 return path
547 }
548
549 /**
550 * Transform an array into a regexp.
551 *
552 * @param {!Array} path
553 * @param {Array=} keys
554 * @param {Object=} options
555 * @return {!RegExp}
556 */
557 function arrayToRegexp (path, keys, options) {
558 var parts = [];
559
560 for (var i = 0; i < path.length; i++) {
561 parts.push(pathToRegexp(path[i], keys, options).source);
562 }
563
564 return new RegExp('(?:' + parts.join('|') + ')', flags(options))
565 }
566
567 /**
568 * Create a path regexp from string input.
569 *
570 * @param {string} path
571 * @param {Array=} keys
572 * @param {Object=} options
573 * @return {!RegExp}
574 */
575 function stringToRegexp (path, keys, options) {
576 return tokensToRegExp(parse(path, options), keys, options)
577 }
578
579 /**
580 * Expose a function for taking tokens and returning a RegExp.
581 *
582 * @param {!Array} tokens
583 * @param {Array=} keys
584 * @param {Object=} options
585 * @return {!RegExp}
586 */
587 function tokensToRegExp (tokens, keys, options) {
588 options = options || {};
589
590 var strict = options.strict;
591 var start = options.start !== false;
592 var end = options.end !== false;
593 var delimiter = escapeString(options.delimiter || DEFAULT_DELIMITER);
594 var delimiters = options.delimiters || DEFAULT_DELIMITERS;
595 var endsWith = [].concat(options.endsWith || []).map(escapeString).concat('$').join('|');
596 var route = start ? '^' : '';
597 var isEndDelimited = tokens.length === 0;
598
599 // Iterate over the tokens and create our regexp string.
600 for (var i = 0; i < tokens.length; i++) {
601 var token = tokens[i];
602
603 if (typeof token === 'string') {
604 route += escapeString(token);
605 isEndDelimited = i === tokens.length - 1 && delimiters.indexOf(token[token.length - 1]) > -1;
606 } else {
607 var capture = token.repeat
608 ? '(?:' + token.pattern + ')(?:' + escapeString(token.delimiter) + '(?:' + token.pattern + '))*'
609 : token.pattern;
610
611 if (keys) keys.push(token);
612
613 if (token.optional) {
614 if (token.partial) {
615 route += escapeString(token.prefix) + '(' + capture + ')?';
616 } else {
617 route += '(?:' + escapeString(token.prefix) + '(' + capture + '))?';
618 }
619 } else {
620 route += escapeString(token.prefix) + '(' + capture + ')';
621 }
622 }
623 }
624
625 if (end) {
626 if (!strict) route += '(?:' + delimiter + ')?';
627
628 route += endsWith === '$' ? '$' : '(?=' + endsWith + ')';
629 } else {
630 if (!strict) route += '(?:' + delimiter + '(?=' + endsWith + '))?';
631 if (!isEndDelimited) route += '(?=' + delimiter + '|' + endsWith + ')';
632 }
633
634 return new RegExp(route, flags(options))
635 }
636
637 /**
638 * Normalize the given path string, returning a regular expression.
639 *
640 * An empty array can be passed in for the keys, which will hold the
641 * placeholder key descriptions. For example, using `/user/:id`, `keys` will
642 * contain `[{ name: 'id', delimiter: '/', optional: false, repeat: false }]`.
643 *
644 * @param {(string|RegExp|Array)} path
645 * @param {Array=} keys
646 * @param {Object=} options
647 * @return {!RegExp}
648 */
649 function pathToRegexp (path, keys, options) {
650 if (path instanceof RegExp) {
651 return regexpToRegexp(path, keys)
652 }
653
654 if (Array.isArray(path)) {
655 return arrayToRegexp(/** @type {!Array} */ (path), keys, options)
656 }
657
658 return stringToRegexp(/** @type {string} */ (path), keys, options)
659 }
660 pathToRegexp_1.parse = parse_1;
661 pathToRegexp_1.compile = compile_1;
662 pathToRegexp_1.tokensToFunction = tokensToFunction_1;
663 pathToRegexp_1.tokensToRegExp = tokensToRegExp_1;
664
665 var withLeadingSlash = function (path) {
666 return path.charAt(0) === "/" ? path : "/" + path;
667 };
668 var withTrailingSlash = function (path) {
669 return path.charAt(path.length - 1) === "/" ? path : path + "/";
670 };
671 var join = function (beginning, end) {
672 return withTrailingSlash(beginning) + end;
673 };
674
675 function createRoute(props, map, parent) {
676 if (parent === void 0) { parent = {
677 path: "",
678 keys: []
679 }; }
680 {
681 if (props.name in map) {
682 throw new Error("Multiple routes have the name \"" + props.name + "\". Route names must be unique.");
683 }
684 if (props.path.charAt(0) === "/") {
685 throw new Error("Route paths cannot start with a forward slash (/). (Received \"" + props.path + "\")");
686 }
687 }
688 var fullPath = withLeadingSlash(join(parent.path, props.path));
689 var _a = props.pathOptions || {}, _b = _a.match, matchOptions = _b === void 0 ? {} : _b, _c = _a.compile, compileOptions = _c === void 0 ? {} : _c;
690 // end must be false for routes with children, but we want to track its original value
691 var exact = matchOptions.end == null || matchOptions.end;
692 if (props.children && props.children.length) {
693 matchOptions.end = false;
694 }
695 var keys = [];
696 var re = pathToRegexp_1(withLeadingSlash(props.path), keys, matchOptions);
697 var keyNames = keys.map(function (key) { return key.name; });
698 if (parent.keys.length) {
699 keyNames = parent.keys.concat(keyNames);
700 }
701 var childRoutes = [];
702 var children = [];
703 if (props.children && props.children.length) {
704 childRoutes = props.children.map(function (child) {
705 return createRoute(child, map, {
706 path: fullPath,
707 keys: keyNames
708 });
709 });
710 children = childRoutes.map(function (child) { return child.public; });
711 }
712 var compiled = pathToRegexp_1.compile(fullPath);
713 var route = {
714 public: {
715 name: props.name,
716 keys: keyNames,
717 parent: undefined,
718 children: children,
719 methods: {
720 resolve: props.resolve,
721 respond: props.respond,
722 pathname: function (params) {
723 return compiled(params, compileOptions);
724 }
725 },
726 extra: props.extra
727 },
728 matching: {
729 re: re,
730 keys: keys,
731 exact: exact,
732 parsers: props.params || {},
733 children: childRoutes
734 }
735 };
736 map[props.name] = route.public;
737 if (childRoutes.length) {
738 childRoutes.forEach(function (child) {
739 child.public.parent = route.public;
740 });
741 }
742 return route;
743 }
744
745 function matchLocation(location, routes) {
746 for (var i = 0, len = routes.length; i < len; i++) {
747 var routeMatches = matchRoute(routes[i], location.pathname);
748 if (routeMatches.length) {
749 return createMatch(routeMatches, location);
750 }
751 }
752 }
753 function matchRoute(route, pathname) {
754 var _a = route.matching, re = _a.re, children = _a.children, exact = _a.exact;
755 var regExpMatch = re.exec(pathname);
756 if (!regExpMatch) {
757 return [];
758 }
759 var matchedSegment = regExpMatch[0], parsed = regExpMatch.slice(1);
760 var matches = [{ route: route, parsed: parsed }];
761 var remainder = pathname.slice(matchedSegment.length);
762 if (!children.length || remainder === "") {
763 return matches;
764 }
765 // match that ends with a strips it from the remainder
766 var fullSegments = withLeadingSlash(remainder);
767 for (var i = 0, length_1 = children.length; i < length_1; i++) {
768 var matched = matchRoute(children[i], fullSegments);
769 if (matched.length) {
770 return matches.concat(matched);
771 }
772 }
773 return exact ? [] : matches;
774 }
775 function createMatch(routeMatches, location) {
776 var route = routeMatches[routeMatches.length - 1].route.public;
777 return {
778 route: route,
779 match: {
780 location: location,
781 name: route.name,
782 params: routeMatches.reduce(function (params, _a) {
783 var route = _a.route, parsed = _a.parsed;
784 parsed.forEach(function (param, index) {
785 var name = route.matching.keys[index].name;
786 var fn = route.matching.parsers[name] || decodeURIComponent;
787 params[name] = fn(param);
788 });
789 return params;
790 }, {})
791 }
792 };
793 }
794
795 function prepareRoutes(routes) {
796 var mappedRoutes = {};
797 var prepared = routes.map(function (route) { return createRoute(route, mappedRoutes); });
798 return {
799 match: function (location) {
800 return matchLocation(location, prepared);
801 },
802 route: function (name) {
803 if (!(name in mappedRoutes)) {
804 console.warn("Attempting to use route \"" + name + "\", but no route with that name exists.");
805 }
806 return mappedRoutes[name];
807 }
808 };
809 }
810
811 function announce(fmt, mode) {
812 if (mode === void 0) { mode = "assertive"; }
813 var announcer = document.createElement("div");
814 announcer.setAttribute("aria-live", mode);
815 // https://hugogiraudel.com/2016/10/13/css-hide-and-seek/
816 announcer.setAttribute("style", [
817 "border: 0 !important;",
818 "clip: rect(1px, 1px, 1px, 1px) !important;",
819 "-webkit-clip-path: inset(50%) !important;",
820 "clip-path: inset(50%) !important;",
821 "height: 1px !important;",
822 "overflow: hidden !important;",
823 "padding: 0 !important;",
824 "position: absolute !important;",
825 "width: 1px !important;",
826 "white-space: nowrap !important;",
827 "top: 0;"
828 ].join(" "));
829 document.body.appendChild(announcer);
830 return function (emitted) {
831 announcer.textContent = fmt(emitted);
832 };
833 }
834
835 function scroll() {
836 return function (_a) {
837 var response = _a.response, navigation = _a.navigation;
838 if (navigation.action === "pop") {
839 return;
840 }
841 // wait until after the re-render to scroll
842 setTimeout(function () {
843 var hash = response.location.hash;
844 if (hash !== "") {
845 var element = document.getElementById(hash);
846 if (element && element.scrollIntoView) {
847 element.scrollIntoView();
848 return;
849 }
850 }
851 // if there is no hash, no element matching the hash,
852 // or the browser doesn't support, we will just scroll
853 // to the top of the page
854 window.scrollTo(0, 0);
855 }, 0);
856 };
857 }
858
859 function title(callback) {
860 return function (emitted) {
861 document.title = callback(emitted);
862 };
863 }
864
865 exports.announce = announce;
866 exports.createRouter = createRouter;
867 exports.prepareRoutes = prepareRoutes;
868 exports.scroll = scroll;
869 exports.title = title;
870
871 Object.defineProperty(exports, '__esModule', { value: true });
872
873}));