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