@solidjs/router 0.4.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js ADDED
@@ -0,0 +1,936 @@
1
+ import { isServer, createComponent as createComponent$1, mergeProps as mergeProps$1, spread, insert, effect, setAttribute, template } from 'solid-js/web';
2
+ import { createSignal, onCleanup, runWithOwner, createMemo, getOwner, createContext, useContext, untrack, useTransition, on, resetErrorBoundaries, createRenderEffect, createComponent, children, createRoot, Show, mergeProps, splitProps } from 'solid-js';
3
+
4
+ function bindEvent(target, type, handler) {
5
+ target.addEventListener(type, handler);
6
+ return () => target.removeEventListener(type, handler);
7
+ }
8
+
9
+ function intercept([value, setValue], get, set) {
10
+ return [get ? () => get(value()) : value, set ? v => setValue(set(v)) : setValue];
11
+ }
12
+
13
+ function querySelector(selector) {
14
+ // Guard against selector being an invalid CSS selector
15
+ try {
16
+ return document.querySelector(selector);
17
+ } catch (e) {
18
+ return null;
19
+ }
20
+ }
21
+
22
+ function scrollToHash(hash, fallbackTop) {
23
+ const el = querySelector(`#${hash}`);
24
+
25
+ if (el) {
26
+ el.scrollIntoView();
27
+ } else if (fallbackTop) {
28
+ window.scrollTo(0, 0);
29
+ }
30
+ }
31
+
32
+ function createIntegration(get, set, init, utils) {
33
+ let ignore = false;
34
+
35
+ const wrap = value => typeof value === "string" ? {
36
+ value
37
+ } : value;
38
+
39
+ const signal = intercept(createSignal(wrap(get()), {
40
+ equals: (a, b) => a.value === b.value
41
+ }), undefined, next => {
42
+ !ignore && set(next);
43
+ return next;
44
+ });
45
+ init && onCleanup(init((value = get()) => {
46
+ ignore = true;
47
+ signal[1](wrap(value));
48
+ ignore = false;
49
+ }));
50
+ return {
51
+ signal,
52
+ utils
53
+ };
54
+ }
55
+ function normalizeIntegration(integration) {
56
+ if (!integration) {
57
+ return {
58
+ signal: createSignal({
59
+ value: ""
60
+ })
61
+ };
62
+ } else if (Array.isArray(integration)) {
63
+ return {
64
+ signal: integration
65
+ };
66
+ }
67
+
68
+ return integration;
69
+ }
70
+ function staticIntegration(obj) {
71
+ return {
72
+ signal: [() => obj, next => Object.assign(obj, next)]
73
+ };
74
+ }
75
+ function pathIntegration() {
76
+ return createIntegration(() => ({
77
+ value: window.location.pathname + window.location.search + window.location.hash,
78
+ state: history.state
79
+ }), ({
80
+ value,
81
+ replace,
82
+ scroll,
83
+ state
84
+ }) => {
85
+ if (replace) {
86
+ window.history.replaceState(state, "", value);
87
+ } else {
88
+ window.history.pushState(state, "", value);
89
+ }
90
+
91
+ scrollToHash(window.location.hash.slice(1), scroll);
92
+ }, notify => bindEvent(window, "popstate", () => notify()), {
93
+ go: delta => window.history.go(delta)
94
+ });
95
+ }
96
+ function hashIntegration() {
97
+ return createIntegration(() => window.location.hash.slice(1), ({
98
+ value,
99
+ replace,
100
+ scroll,
101
+ state
102
+ }) => {
103
+ if (replace) {
104
+ window.history.replaceState(state, "", "#" + value);
105
+ } else {
106
+ window.location.hash = value;
107
+ }
108
+
109
+ const hashIndex = value.indexOf("#");
110
+ const hash = hashIndex >= 0 ? value.slice(hashIndex + 1) : "";
111
+ scrollToHash(hash, scroll);
112
+ }, notify => bindEvent(window, "hashchange", () => notify()), {
113
+ go: delta => window.history.go(delta),
114
+ renderPath: path => `#${path}`,
115
+ parsePath: str => {
116
+ const to = str.replace(/^.*?#/, ""); // Hash-only hrefs like `#foo` from plain anchors will come in as `/#foo` whereas a link to
117
+ // `/foo` will be `/#/foo`. Check if the to starts with a `/` and if not append it as a hash
118
+ // to the current path so we can handle these in-page anchors correctly.
119
+
120
+ if (!to.startsWith("/")) {
121
+ const [, path = "/"] = window.location.hash.split("#", 2);
122
+ return `${path}#${to}`;
123
+ }
124
+
125
+ return to;
126
+ }
127
+ });
128
+ }
129
+
130
+ const hasSchemeRegex = /^(?:[a-z0-9]+:)?\/\//i;
131
+ const trimPathRegex = /^\/+|\/+$/g;
132
+
133
+ function normalize(path, omitSlash = false) {
134
+ const s = path.replace(trimPathRegex, "");
135
+ return s ? omitSlash || /^[?#]/.test(s) ? s : "/" + s : "";
136
+ }
137
+
138
+ function resolvePath(base, path, from) {
139
+ if (hasSchemeRegex.test(path)) {
140
+ return undefined;
141
+ }
142
+
143
+ const basePath = normalize(base);
144
+ const fromPath = from && normalize(from);
145
+ let result = "";
146
+
147
+ if (!fromPath || path.startsWith("/")) {
148
+ result = basePath;
149
+ } else if (fromPath.toLowerCase().indexOf(basePath.toLowerCase()) !== 0) {
150
+ result = basePath + fromPath;
151
+ } else {
152
+ result = fromPath;
153
+ }
154
+
155
+ return (result || "/") + normalize(path, !result);
156
+ }
157
+ function invariant(value, message) {
158
+ if (value == null) {
159
+ throw new Error(message);
160
+ }
161
+
162
+ return value;
163
+ }
164
+ function joinPaths(from, to) {
165
+ return normalize(from).replace(/\/*(\*.*)?$/g, "") + normalize(to);
166
+ }
167
+ function extractSearchParams(url) {
168
+ const params = {};
169
+ url.searchParams.forEach((value, key) => {
170
+ params[key] = value;
171
+ });
172
+ return params;
173
+ }
174
+ function urlDecode(str, isQuery) {
175
+ return decodeURIComponent(isQuery ? str.replace(/\+/g, " ") : str);
176
+ }
177
+ function createMatcher(path, partial) {
178
+ const [pattern, splat] = path.split("/*", 2);
179
+ const segments = pattern.split("/").filter(Boolean);
180
+ const len = segments.length;
181
+ return location => {
182
+ const locSegments = location.split("/").filter(Boolean);
183
+ const lenDiff = locSegments.length - len;
184
+
185
+ if (lenDiff < 0 || lenDiff > 0 && splat === undefined && !partial) {
186
+ return null;
187
+ }
188
+
189
+ const match = {
190
+ path: len ? "" : "/",
191
+ params: {}
192
+ };
193
+
194
+ for (let i = 0; i < len; i++) {
195
+ const segment = segments[i];
196
+ const locSegment = locSegments[i];
197
+
198
+ if (segment[0] === ":") {
199
+ match.params[segment.slice(1)] = locSegment;
200
+ } else if (segment.localeCompare(locSegment, undefined, {
201
+ sensitivity: "base"
202
+ }) !== 0) {
203
+ return null;
204
+ }
205
+
206
+ match.path += `/${locSegment}`;
207
+ }
208
+
209
+ if (splat) {
210
+ match.params[splat] = lenDiff ? locSegments.slice(-lenDiff).join("/") : "";
211
+ }
212
+
213
+ return match;
214
+ };
215
+ }
216
+ function scoreRoute(route) {
217
+ const [pattern, splat] = route.pattern.split("/*", 2);
218
+ const segments = pattern.split("/").filter(Boolean);
219
+ return segments.reduce((score, segment) => score + (segment.startsWith(":") ? 2 : 3), segments.length - (splat === undefined ? 0 : 1));
220
+ }
221
+ function createMemoObject(fn) {
222
+ const map = new Map();
223
+ const owner = getOwner();
224
+ return new Proxy({}, {
225
+ get(_, property) {
226
+ if (!map.has(property)) {
227
+ runWithOwner(owner, () => map.set(property, createMemo(() => fn()[property])));
228
+ }
229
+
230
+ return map.get(property)();
231
+ },
232
+
233
+ getOwnPropertyDescriptor() {
234
+ return {
235
+ enumerable: true,
236
+ configurable: true
237
+ };
238
+ },
239
+
240
+ ownKeys() {
241
+ return Reflect.ownKeys(fn());
242
+ }
243
+
244
+ });
245
+ }
246
+ function mergeSearchString(search, params) {
247
+ const merged = new URLSearchParams(search);
248
+ Object.entries(params).forEach(([key, value]) => {
249
+ if (value == null || value === "") {
250
+ merged.delete(key);
251
+ } else {
252
+ merged.set(key, String(value));
253
+ }
254
+ });
255
+ const s = merged.toString();
256
+ return s ? `?${s}` : "";
257
+ }
258
+ function expandOptionals(pattern) {
259
+ let match = /(\/?\:[^\/]+)\?/.exec(pattern);
260
+ if (!match) return [pattern];
261
+ let prefix = pattern.slice(0, match.index);
262
+ let suffix = pattern.slice(match.index + match[0].length);
263
+ const prefixes = [prefix, prefix += match[1]]; // This section handles adjacent optional params. We don't actually want all permuations since
264
+ // that will lead to equivalent routes which have the same number of params. For example
265
+ // `/:a?/:b?/:c`? only has the unique expansion: `/`, `/:a`, `/:a/:b`, `/:a/:b/:c` and we can
266
+ // discard `/:b`, `/:c`, `/:b/:c` by building them up in order and not recursing. This also helps
267
+ // ensure predictability where earlier params have precidence.
268
+
269
+ while (match = /^(\/\:[^\/]+)\?/.exec(suffix)) {
270
+ prefixes.push(prefix += match[1]);
271
+ suffix = suffix.slice(match[0].length);
272
+ }
273
+
274
+ return expandOptionals(suffix).reduce((results, expansion) => [...results, ...prefixes.map(p => p + expansion)], []);
275
+ }
276
+
277
+ const MAX_REDIRECTS = 100;
278
+ const RouterContextObj = createContext();
279
+ const RouteContextObj = createContext();
280
+ const useRouter = () => invariant(useContext(RouterContextObj), "Make sure your app is wrapped in a <Router />");
281
+ let TempRoute;
282
+ const useRoute = () => TempRoute || useContext(RouteContextObj) || useRouter().base;
283
+ const useResolvedPath = path => {
284
+ const route = useRoute();
285
+ return createMemo(() => route.resolvePath(path()));
286
+ };
287
+ const useHref = to => {
288
+ const router = useRouter();
289
+ return createMemo(() => {
290
+ const to_ = to();
291
+ return to_ !== undefined ? router.renderPath(to_) : to_;
292
+ });
293
+ };
294
+ const useNavigate = () => useRouter().navigatorFactory();
295
+ const useLocation = () => useRouter().location;
296
+ const useIsRouting = () => useRouter().isRouting;
297
+ const useMatch = path => {
298
+ const location = useLocation();
299
+ const matcher = createMemo(() => createMatcher(path()));
300
+ return createMemo(() => matcher()(location.pathname));
301
+ };
302
+ const useParams = () => useRoute().params;
303
+ const useRouteData = () => useRoute().data;
304
+ const useSearchParams = () => {
305
+ const location = useLocation();
306
+ const navigate = useNavigate();
307
+
308
+ const setSearchParams = (params, options) => {
309
+ const searchString = untrack(() => mergeSearchString(location.search, params));
310
+ navigate(searchString, {
311
+ scroll: false,
312
+ ...options,
313
+ resolve: true
314
+ });
315
+ };
316
+
317
+ return [location.query, setSearchParams];
318
+ };
319
+ function createRoutes(routeDef, base = "", fallback) {
320
+ const {
321
+ component,
322
+ data,
323
+ children
324
+ } = routeDef;
325
+ const isLeaf = !children || Array.isArray(children) && !children.length;
326
+ const shared = {
327
+ key: routeDef,
328
+ element: component ? () => createComponent(component, {}) : () => {
329
+ const {
330
+ element
331
+ } = routeDef;
332
+ return element === undefined && fallback ? createComponent(fallback, {}) : element;
333
+ },
334
+ preload: routeDef.component ? component.preload : routeDef.preload,
335
+ data
336
+ };
337
+ return asArray(routeDef.path).reduce((acc, path) => {
338
+ for (const originalPath of expandOptionals(path)) {
339
+ const path = joinPaths(base, originalPath);
340
+ const pattern = isLeaf ? path : path.split("/*", 1)[0];
341
+ acc.push({ ...shared,
342
+ originalPath,
343
+ pattern,
344
+ matcher: createMatcher(pattern, !isLeaf)
345
+ });
346
+ }
347
+
348
+ return acc;
349
+ }, []);
350
+ }
351
+ function createBranch(routes, index = 0) {
352
+ return {
353
+ routes,
354
+ score: scoreRoute(routes[routes.length - 1]) * 10000 - index,
355
+
356
+ matcher(location) {
357
+ const matches = [];
358
+
359
+ for (let i = routes.length - 1; i >= 0; i--) {
360
+ const route = routes[i];
361
+ const match = route.matcher(location);
362
+
363
+ if (!match) {
364
+ return null;
365
+ }
366
+
367
+ matches.unshift({ ...match,
368
+ route
369
+ });
370
+ }
371
+
372
+ return matches;
373
+ }
374
+
375
+ };
376
+ }
377
+
378
+ function asArray(value) {
379
+ return Array.isArray(value) ? value : [value];
380
+ }
381
+
382
+ function createBranches(routeDef, base = "", fallback, stack = [], branches = []) {
383
+ const routeDefs = asArray(routeDef);
384
+
385
+ for (let i = 0, len = routeDefs.length; i < len; i++) {
386
+ const def = routeDefs[i];
387
+
388
+ if (def && typeof def === "object" && def.hasOwnProperty("path")) {
389
+ const routes = createRoutes(def, base, fallback);
390
+
391
+ for (const route of routes) {
392
+ stack.push(route);
393
+
394
+ if (def.children) {
395
+ createBranches(def.children, route.pattern, fallback, stack, branches);
396
+ } else {
397
+ const branch = createBranch([...stack], branches.length);
398
+ branches.push(branch);
399
+ }
400
+
401
+ stack.pop();
402
+ }
403
+ }
404
+ } // Stack will be empty on final return
405
+
406
+
407
+ return stack.length ? branches : branches.sort((a, b) => b.score - a.score);
408
+ }
409
+ function getRouteMatches(branches, location) {
410
+ for (let i = 0, len = branches.length; i < len; i++) {
411
+ const match = branches[i].matcher(location);
412
+
413
+ if (match) {
414
+ return match;
415
+ }
416
+ }
417
+
418
+ return [];
419
+ }
420
+ function createLocation(path, state) {
421
+ const origin = new URL("http://sar");
422
+ const url = createMemo(prev => {
423
+ const path_ = path();
424
+
425
+ try {
426
+ return new URL(path_, origin);
427
+ } catch (err) {
428
+ console.error(`Invalid path ${path_}`);
429
+ return prev;
430
+ }
431
+ }, origin, {
432
+ equals: (a, b) => a.href === b.href
433
+ });
434
+ const pathname = createMemo(() => urlDecode(url().pathname));
435
+ const search = createMemo(() => urlDecode(url().search, true));
436
+ const hash = createMemo(() => urlDecode(url().hash));
437
+ const key = createMemo(() => "");
438
+ return {
439
+ get pathname() {
440
+ return pathname();
441
+ },
442
+
443
+ get search() {
444
+ return search();
445
+ },
446
+
447
+ get hash() {
448
+ return hash();
449
+ },
450
+
451
+ get state() {
452
+ return state();
453
+ },
454
+
455
+ get key() {
456
+ return key();
457
+ },
458
+
459
+ query: createMemoObject(on(search, () => extractSearchParams(url())))
460
+ };
461
+ }
462
+ function createRouterContext(integration, base = "", data, out) {
463
+ const {
464
+ signal: [source, setSource],
465
+ utils = {}
466
+ } = normalizeIntegration(integration);
467
+
468
+ const parsePath = utils.parsePath || (p => p);
469
+
470
+ const renderPath = utils.renderPath || (p => p);
471
+
472
+ const basePath = resolvePath("", base);
473
+ const output = isServer && out ? Object.assign(out, {
474
+ matches: [],
475
+ url: undefined
476
+ }) : undefined;
477
+
478
+ if (basePath === undefined) {
479
+ throw new Error(`${basePath} is not a valid base path`);
480
+ } else if (basePath && !source().value) {
481
+ setSource({
482
+ value: basePath,
483
+ replace: true,
484
+ scroll: false
485
+ });
486
+ }
487
+
488
+ const [isRouting, start] = useTransition();
489
+ const [reference, setReference] = createSignal(source().value);
490
+ const [state, setState] = createSignal(source().state);
491
+ const location = createLocation(reference, state);
492
+ const referrers = [];
493
+ const baseRoute = {
494
+ pattern: basePath,
495
+ params: {},
496
+ path: () => basePath,
497
+ outlet: () => null,
498
+
499
+ resolvePath(to) {
500
+ return resolvePath(basePath, to);
501
+ }
502
+
503
+ };
504
+
505
+ if (data) {
506
+ try {
507
+ TempRoute = baseRoute;
508
+ baseRoute.data = data({
509
+ data: undefined,
510
+ params: {},
511
+ location,
512
+ navigate: navigatorFactory(baseRoute)
513
+ });
514
+ } finally {
515
+ TempRoute = undefined;
516
+ }
517
+ }
518
+
519
+ function navigateFromRoute(route, to, options) {
520
+ // Untrack in case someone navigates in an effect - don't want to track `reference` or route paths
521
+ untrack(() => {
522
+ if (typeof to === "number") {
523
+ if (!to) ; else if (utils.go) {
524
+ utils.go(to);
525
+ } else {
526
+ console.warn("Router integration does not support relative routing");
527
+ }
528
+
529
+ return;
530
+ }
531
+
532
+ const {
533
+ replace,
534
+ resolve,
535
+ scroll,
536
+ state: nextState
537
+ } = {
538
+ replace: false,
539
+ resolve: true,
540
+ scroll: true,
541
+ ...options
542
+ };
543
+ const resolvedTo = resolve ? route.resolvePath(to) : resolvePath("", to);
544
+
545
+ if (resolvedTo === undefined) {
546
+ throw new Error(`Path '${to}' is not a routable path`);
547
+ } else if (referrers.length >= MAX_REDIRECTS) {
548
+ throw new Error("Too many redirects");
549
+ }
550
+
551
+ const current = reference();
552
+
553
+ if (resolvedTo !== current || nextState !== state()) {
554
+ if (isServer) {
555
+ if (output) {
556
+ output.url = resolvedTo;
557
+ }
558
+
559
+ setSource({
560
+ value: resolvedTo,
561
+ replace,
562
+ scroll,
563
+ state: nextState
564
+ });
565
+ } else {
566
+ const len = referrers.push({
567
+ value: current,
568
+ replace,
569
+ scroll,
570
+ state: state()
571
+ });
572
+ start(() => {
573
+ setReference(resolvedTo);
574
+ setState(nextState);
575
+ resetErrorBoundaries();
576
+ }).then(() => {
577
+ if (referrers.length === len) {
578
+ navigateEnd({
579
+ value: resolvedTo,
580
+ state: nextState
581
+ });
582
+ }
583
+ });
584
+ }
585
+ }
586
+ });
587
+ }
588
+
589
+ function navigatorFactory(route) {
590
+ // Workaround for vite issue (https://github.com/vitejs/vite/issues/3803)
591
+ route = route || useContext(RouteContextObj) || baseRoute;
592
+ return (to, options) => navigateFromRoute(route, to, options);
593
+ }
594
+
595
+ function navigateEnd(next) {
596
+ const first = referrers[0];
597
+
598
+ if (first) {
599
+ if (next.value !== first.value || next.state !== first.state) {
600
+ setSource({ ...next,
601
+ replace: first.replace,
602
+ scroll: first.scroll
603
+ });
604
+ }
605
+
606
+ referrers.length = 0;
607
+ }
608
+ }
609
+
610
+ createRenderEffect(() => {
611
+ const {
612
+ value,
613
+ state
614
+ } = source(); // Untrack this whole block so `start` doesn't cause Solid's Listener to be preserved
615
+
616
+ untrack(() => {
617
+ if (value !== reference()) {
618
+ start(() => {
619
+ setReference(value);
620
+ setState(state);
621
+ });
622
+ }
623
+ });
624
+ });
625
+
626
+ if (!isServer) {
627
+ function isSvg(el) {
628
+ return el.namespaceURI === "http://www.w3.org/2000/svg";
629
+ }
630
+
631
+ function handleAnchorClick(evt) {
632
+ if (evt.defaultPrevented || evt.button !== 0 || evt.metaKey || evt.altKey || evt.ctrlKey || evt.shiftKey) return;
633
+ const a = evt.composedPath().find(el => el instanceof Node && el.nodeName.toUpperCase() === "A");
634
+ if (!a) return;
635
+ const svg = isSvg(a);
636
+ const href = svg ? a.href.baseVal : a.href;
637
+ const target = svg ? a.target.baseVal : a.target;
638
+ if (target || !href && !a.hasAttribute("state")) return;
639
+ const rel = (a.getAttribute("rel") || "").split(/\s+/);
640
+ if (a.hasAttribute("download") || rel && rel.includes("external")) return;
641
+ const url = svg ? new URL(href, document.baseURI) : new URL(href);
642
+ const pathname = urlDecode(url.pathname);
643
+ if (url.origin !== window.location.origin || basePath && pathname && !pathname.toLowerCase().startsWith(basePath.toLowerCase())) return;
644
+ const to = parsePath(pathname + urlDecode(url.search, true) + urlDecode(url.hash));
645
+ const state = a.getAttribute("state");
646
+ evt.preventDefault();
647
+ navigateFromRoute(baseRoute, to, {
648
+ resolve: false,
649
+ replace: a.hasAttribute("replace"),
650
+ scroll: !a.hasAttribute("noscroll"),
651
+ state: state && JSON.parse(state)
652
+ });
653
+ }
654
+
655
+ document.addEventListener("click", handleAnchorClick);
656
+ onCleanup(() => document.removeEventListener("click", handleAnchorClick));
657
+ }
658
+
659
+ return {
660
+ base: baseRoute,
661
+ out: output,
662
+ location,
663
+ isRouting,
664
+ renderPath,
665
+ parsePath,
666
+ navigatorFactory
667
+ };
668
+ }
669
+ function createRouteContext(router, parent, child, match) {
670
+ const {
671
+ base,
672
+ location,
673
+ navigatorFactory
674
+ } = router;
675
+ const {
676
+ pattern,
677
+ element: outlet,
678
+ preload,
679
+ data
680
+ } = match().route;
681
+ const path = createMemo(() => match().path);
682
+ const params = createMemoObject(() => match().params);
683
+ preload && preload();
684
+ const route = {
685
+ parent,
686
+ pattern,
687
+
688
+ get child() {
689
+ return child();
690
+ },
691
+
692
+ path,
693
+ params,
694
+ data: parent.data,
695
+ outlet,
696
+
697
+ resolvePath(to) {
698
+ return resolvePath(base.path(), to, path());
699
+ }
700
+
701
+ };
702
+
703
+ if (data) {
704
+ try {
705
+ TempRoute = route;
706
+ route.data = data({
707
+ data: parent.data,
708
+ params,
709
+ location,
710
+ navigate: navigatorFactory(route)
711
+ });
712
+ } finally {
713
+ TempRoute = undefined;
714
+ }
715
+ }
716
+
717
+ return route;
718
+ }
719
+
720
+ const _tmpl$ = /*#__PURE__*/template(`<a></a>`, 2);
721
+ const Router = props => {
722
+ const {
723
+ source,
724
+ url,
725
+ base,
726
+ data,
727
+ out
728
+ } = props;
729
+ const integration = source || (isServer ? staticIntegration({
730
+ value: url || ""
731
+ }) : pathIntegration());
732
+ const routerState = createRouterContext(integration, base, data, out);
733
+ return createComponent$1(RouterContextObj.Provider, {
734
+ value: routerState,
735
+
736
+ get children() {
737
+ return props.children;
738
+ }
739
+
740
+ });
741
+ };
742
+ const Routes = props => {
743
+ const router = useRouter();
744
+ const parentRoute = useRoute();
745
+ const routeDefs = children(() => props.children);
746
+ const branches = createMemo(() => createBranches(routeDefs(), joinPaths(parentRoute.pattern, props.base || ""), Outlet));
747
+ const matches = createMemo(() => getRouteMatches(branches(), router.location.pathname));
748
+
749
+ if (router.out) {
750
+ router.out.matches.push(matches().map(({
751
+ route,
752
+ path,
753
+ params
754
+ }) => ({
755
+ originalPath: route.originalPath,
756
+ pattern: route.pattern,
757
+ path,
758
+ params
759
+ })));
760
+ }
761
+
762
+ const disposers = [];
763
+ let root;
764
+ const routeStates = createMemo(on(matches, (nextMatches, prevMatches, prev) => {
765
+ let equal = prevMatches && nextMatches.length === prevMatches.length;
766
+ const next = [];
767
+
768
+ for (let i = 0, len = nextMatches.length; i < len; i++) {
769
+ const prevMatch = prevMatches && prevMatches[i];
770
+ const nextMatch = nextMatches[i];
771
+
772
+ if (prev && prevMatch && nextMatch.route.key === prevMatch.route.key) {
773
+ next[i] = prev[i];
774
+ } else {
775
+ equal = false;
776
+
777
+ if (disposers[i]) {
778
+ disposers[i]();
779
+ }
780
+
781
+ createRoot(dispose => {
782
+ disposers[i] = dispose;
783
+ next[i] = createRouteContext(router, next[i - 1] || parentRoute, () => routeStates()[i + 1], () => matches()[i]);
784
+ });
785
+ }
786
+ }
787
+
788
+ disposers.splice(nextMatches.length).forEach(dispose => dispose());
789
+
790
+ if (prev && equal) {
791
+ return prev;
792
+ }
793
+
794
+ root = next[0];
795
+ return next;
796
+ }));
797
+ return createComponent$1(Show, {
798
+ get when() {
799
+ return routeStates() && root;
800
+ },
801
+
802
+ children: route => createComponent$1(RouteContextObj.Provider, {
803
+ value: route,
804
+
805
+ get children() {
806
+ return route.outlet();
807
+ }
808
+
809
+ })
810
+ });
811
+ };
812
+ const useRoutes = (routes, base) => {
813
+ return () => createComponent$1(Routes, {
814
+ base: base,
815
+ children: routes
816
+ });
817
+ };
818
+ const Route = props => {
819
+ const childRoutes = children(() => props.children);
820
+ return mergeProps(props, {
821
+ get children() {
822
+ return childRoutes();
823
+ }
824
+
825
+ });
826
+ };
827
+ const Outlet = () => {
828
+ const route = useRoute();
829
+ return createComponent$1(Show, {
830
+ get when() {
831
+ return route.child;
832
+ },
833
+
834
+ children: child => createComponent$1(RouteContextObj.Provider, {
835
+ value: child,
836
+
837
+ get children() {
838
+ return child.outlet();
839
+ }
840
+
841
+ })
842
+ });
843
+ };
844
+
845
+ function LinkBase(props) {
846
+ const [, rest] = splitProps(props, ["children", "to", "href", "state"]);
847
+ const href = useHref(() => props.to);
848
+ return (() => {
849
+ const _el$ = _tmpl$.cloneNode(true);
850
+
851
+ spread(_el$, rest, false, true);
852
+
853
+ insert(_el$, () => props.children);
854
+
855
+ effect(_p$ => {
856
+ const _v$ = href() || props.href,
857
+ _v$2 = JSON.stringify(props.state);
858
+
859
+ _v$ !== _p$._v$ && setAttribute(_el$, "href", _p$._v$ = _v$);
860
+ _v$2 !== _p$._v$2 && setAttribute(_el$, "state", _p$._v$2 = _v$2);
861
+ return _p$;
862
+ }, {
863
+ _v$: undefined,
864
+ _v$2: undefined
865
+ });
866
+
867
+ return _el$;
868
+ })();
869
+ }
870
+
871
+ function Link(props) {
872
+ const to = useResolvedPath(() => props.href);
873
+ return createComponent$1(LinkBase, mergeProps$1(props, {
874
+ get to() {
875
+ return to();
876
+ }
877
+
878
+ }));
879
+ }
880
+ function NavLink(props) {
881
+ props = mergeProps({
882
+ inactiveClass: "inactive",
883
+ activeClass: "active"
884
+ }, props);
885
+ const [, rest] = splitProps(props, ["activeClass", "inactiveClass", "end"]);
886
+ const location = useLocation();
887
+ const to = useResolvedPath(() => props.href);
888
+ const isActive = createMemo(() => {
889
+ const to_ = to();
890
+
891
+ if (to_ === undefined) {
892
+ return false;
893
+ }
894
+
895
+ const path = to_.split(/[?#]/, 1)[0].toLowerCase();
896
+ const loc = location.pathname.toLowerCase();
897
+ return props.end ? path === loc : loc.startsWith(path);
898
+ });
899
+ return createComponent$1(LinkBase, mergeProps$1(rest, {
900
+ get to() {
901
+ return to();
902
+ },
903
+
904
+ get classList() {
905
+ return {
906
+ [props.inactiveClass]: !isActive(),
907
+ [props.activeClass]: isActive(),
908
+ ...rest.classList
909
+ };
910
+ },
911
+
912
+ get ["aria-current"]() {
913
+ return isActive() ? "page" : undefined;
914
+ }
915
+
916
+ }));
917
+ }
918
+ function Navigate(props) {
919
+ const navigate = useNavigate();
920
+ const location = useLocation();
921
+ const {
922
+ href,
923
+ state
924
+ } = props;
925
+ const path = typeof href === "function" ? href({
926
+ navigate,
927
+ location
928
+ }) : href;
929
+ navigate(path, {
930
+ replace: true,
931
+ state
932
+ });
933
+ return null;
934
+ }
935
+
936
+ export { Link, NavLink, Navigate, Outlet, Route, Router, Routes, mergeSearchString as _mergeSearchString, createIntegration, hashIntegration, normalizeIntegration, pathIntegration, staticIntegration, useHref, useIsRouting, useLocation, useMatch, useNavigate, useParams, useResolvedPath, useRouteData, useRoutes, useSearchParams };