@solidjs/router 2.0.0-next.30 → 2.0.0-next.31
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 +1 -1
- package/dist/data/action.js +31 -22
- package/dist/data/events.js +1 -1
- package/dist/data/query.js +9 -10
- package/dist/fs.d.ts +1 -1
- package/dist/fs.js +1 -1
- package/dist/index.js +77 -81
- package/dist/paths.js +2 -6
- package/dist/routers/components.jsx +1 -3
- package/dist/routers/factory.jsx +1 -2
- package/dist/routers/history.js +7 -11
- package/dist/routers/scrollRestoration.js +1 -2
- package/dist/routing.js +9 -17
- package/dist/utils.js +12 -22
- package/package.json +5 -5
package/README.md
CHANGED
|
@@ -850,7 +850,7 @@ const isRouting = useIsRouting();
|
|
|
850
850
|
return <div classList={{ "grey-out": isRouting() }}>...</div>;
|
|
851
851
|
```
|
|
852
852
|
|
|
853
|
-
In Solid's dev and observe builds the router also declares every navigation to the attribution engine (`solid-js/attribution`): holds and re-runs caused by a navigation are named after the route pattern (`navigation to /users/:id`), timed from the user event that started it, and redirect hops fold onto the navigation they belong to. `attribution.
|
|
853
|
+
In Solid's dev and observe builds the router also declares every navigation to the attribution engine (`solid-js/attribution`): holds and re-runs caused by a navigation are named after the route pattern (`navigation to /users/:id`), timed from the user event that started it, and redirect hops fold onto the navigation they belong to. `attribution.history("navigation")` and `feedback().navigations` list them; nothing of this exists in production builds.
|
|
854
854
|
|
|
855
855
|
### useMatch
|
|
856
856
|
|
package/dist/data/action.js
CHANGED
|
@@ -29,9 +29,10 @@ export const actions = /* #__PURE__ */ new Map();
|
|
|
29
29
|
export function handleFormAction(evt, router, actionBase) {
|
|
30
30
|
if (evt.defaultPrevented)
|
|
31
31
|
return;
|
|
32
|
+
const form = evt.target;
|
|
32
33
|
let actionRef = evt.submitter && evt.submitter.hasAttribute("formaction")
|
|
33
34
|
? evt.submitter.getAttribute("formaction")
|
|
34
|
-
:
|
|
35
|
+
: form.getAttribute("action");
|
|
35
36
|
if (!actionRef)
|
|
36
37
|
return;
|
|
37
38
|
const serverAction = !actionRef.startsWith("https://action/");
|
|
@@ -42,7 +43,7 @@ export function handleFormAction(evt, router, actionBase) {
|
|
|
42
43
|
if (!actionRef.startsWith(actionBase))
|
|
43
44
|
return;
|
|
44
45
|
}
|
|
45
|
-
if (
|
|
46
|
+
if (form.method.toUpperCase() !== "POST")
|
|
46
47
|
throw new Error("Only POST forms are supported for Actions");
|
|
47
48
|
// A registry miss on a server-action url is a direct bind whose module
|
|
48
49
|
// never loaded client-side (server components): the url is self-describing
|
|
@@ -54,10 +55,8 @@ export function handleFormAction(evt, router, actionBase) {
|
|
|
54
55
|
const handler = actions.get(actionRef) || (serverAction && createServerFormAction(actionRef));
|
|
55
56
|
if (handler) {
|
|
56
57
|
evt.preventDefault();
|
|
57
|
-
const data = new FormData(
|
|
58
|
-
handler.call({ r: router, f:
|
|
59
|
-
? data
|
|
60
|
-
: new URLSearchParams(data));
|
|
58
|
+
const data = new FormData(form, evt.submitter);
|
|
59
|
+
handler.call({ r: router, f: form }, form.enctype === "multipart/form-data" ? data : new URLSearchParams(data));
|
|
61
60
|
}
|
|
62
61
|
}
|
|
63
62
|
/**
|
|
@@ -159,18 +158,22 @@ function actionImpl(fn, options = {}) {
|
|
|
159
158
|
const runMutation = () => fn(...variables);
|
|
160
159
|
const run = createSolidAction(async function* (context) {
|
|
161
160
|
context.optimistic?.();
|
|
161
|
+
let value;
|
|
162
|
+
let error = false;
|
|
162
163
|
try {
|
|
163
|
-
|
|
164
|
-
yield;
|
|
165
|
-
return { error: false, value };
|
|
164
|
+
value = await context.call();
|
|
166
165
|
}
|
|
167
|
-
catch (
|
|
168
|
-
|
|
169
|
-
|
|
166
|
+
catch (e) {
|
|
167
|
+
value = e;
|
|
168
|
+
error = true;
|
|
170
169
|
}
|
|
170
|
+
const read = await readResponse(value, error);
|
|
171
|
+
yield;
|
|
172
|
+
// Apply inside the transition so the default revalidation's refetch and
|
|
173
|
+
// the release of the caller's optimistic writes commit as one frame (#619).
|
|
174
|
+
return applyResponse(read, router.navigatorFactory(), flightApplications !== flightApplicationsBefore);
|
|
171
175
|
});
|
|
172
176
|
form && setFormBusy(form, 1);
|
|
173
|
-
let settled;
|
|
174
177
|
let response;
|
|
175
178
|
// The transport consumer is awaited before a single-flight mutation
|
|
176
179
|
// resolves, so a counter delta over the call tells whether this action's
|
|
@@ -180,7 +183,7 @@ function actionImpl(fn, options = {}) {
|
|
|
180
183
|
// which misses every response the server returned without flight data.
|
|
181
184
|
const flightApplicationsBefore = flightApplications;
|
|
182
185
|
try {
|
|
183
|
-
|
|
186
|
+
response = await settleActionResult(run({
|
|
184
187
|
call: runMutation,
|
|
185
188
|
optimistic: submitHooks.size
|
|
186
189
|
? () => {
|
|
@@ -189,7 +192,6 @@ function actionImpl(fn, options = {}) {
|
|
|
189
192
|
}
|
|
190
193
|
: undefined
|
|
191
194
|
}));
|
|
192
|
-
response = await handleResponse(settled.value, settled.error, router.navigatorFactory(), flightApplications !== flightApplicationsBefore);
|
|
193
195
|
}
|
|
194
196
|
finally {
|
|
195
197
|
form && setFormBusy(form, -1);
|
|
@@ -198,8 +200,8 @@ function actionImpl(fn, options = {}) {
|
|
|
198
200
|
submission = {
|
|
199
201
|
input: variables,
|
|
200
202
|
url,
|
|
201
|
-
result: response
|
|
202
|
-
error: response
|
|
203
|
+
result: response?.data,
|
|
204
|
+
error: response?.error,
|
|
203
205
|
clear() {
|
|
204
206
|
router.submissions[1](entries => entries.filter(entry => entry !== submission));
|
|
205
207
|
},
|
|
@@ -244,8 +246,7 @@ function toAction(invoke, url, boundArgs = [], base = url, submitHooks = new Map
|
|
|
244
246
|
fn.with = function (...args) {
|
|
245
247
|
const uri = new URL(url, mockBase);
|
|
246
248
|
uri.searchParams.set("args", hashKey(args));
|
|
247
|
-
|
|
248
|
-
return next;
|
|
249
|
+
return toAction(invoke, (uri.origin === "https://action" ? uri.origin : "") + uri.pathname + uri.search, [...boundArgs, ...args], base, submitHooks, settledHooks);
|
|
249
250
|
};
|
|
250
251
|
fn.onSubmit = function (hook) {
|
|
251
252
|
const id = Symbol("actionOnSubmitHook");
|
|
@@ -362,8 +363,10 @@ function applyResponseMetadata(metadata, navigate, flightData) {
|
|
|
362
363
|
cacheKeyOp(keys, entry => (entry[0] = 0));
|
|
363
364
|
// set cache — and fan the payload out to other keyed stores (live query
|
|
364
365
|
// channels adopt delivered values instead of reconnecting)
|
|
365
|
-
|
|
366
|
-
|
|
366
|
+
if (flightData) {
|
|
367
|
+
Object.keys(flightData).forEach(k => query.set(k, flightData[k]));
|
|
368
|
+
deliverFlightData(flightData);
|
|
369
|
+
}
|
|
367
370
|
// trigger revalidation inside the same transition as the navigation, so
|
|
368
371
|
// the redirect commits atomically with fresh data: surviving consumers
|
|
369
372
|
// (shared layouts) the flight payload didn't seed refetch and hold the
|
|
@@ -371,7 +374,7 @@ function applyResponseMetadata(metadata, navigate, flightData) {
|
|
|
371
374
|
// are fresh again by now, so the sweep re-reads them from cache.
|
|
372
375
|
revalidate(keys, false);
|
|
373
376
|
}
|
|
374
|
-
async function
|
|
377
|
+
async function readResponse(response, error) {
|
|
375
378
|
let data;
|
|
376
379
|
let flightData;
|
|
377
380
|
let metadata;
|
|
@@ -397,6 +400,12 @@ async function handleResponse(response, error, navigate, metadataHandled) {
|
|
|
397
400
|
return { error: response };
|
|
398
401
|
else
|
|
399
402
|
data = response;
|
|
403
|
+
return { data, flightData, metadata };
|
|
404
|
+
}
|
|
405
|
+
function applyResponse(read, navigate, metadataHandled) {
|
|
406
|
+
if ("error" in read)
|
|
407
|
+
return read;
|
|
408
|
+
const { data, flightData, metadata } = read;
|
|
400
409
|
// The transport consumer applies metadata before returning a server
|
|
401
410
|
// function's unwrapped value. Do not treat that value as a second plain
|
|
402
411
|
// action response and invalidate the freshly seeded query cache again.
|
package/dist/data/events.js
CHANGED
|
@@ -32,7 +32,7 @@ export function setupNativeEvents({ preload = true, explicitLinks = false, actio
|
|
|
32
32
|
if (target || (!href && !a.hasAttribute("state")))
|
|
33
33
|
return;
|
|
34
34
|
const rel = (a.getAttribute("rel") || "").split(/\s+/);
|
|
35
|
-
if (a.hasAttribute("download") ||
|
|
35
|
+
if (a.hasAttribute("download") || rel.includes("external"))
|
|
36
36
|
return;
|
|
37
37
|
const url = svg ? new URL(href, document.baseURI) : new URL(href);
|
|
38
38
|
// Skip non-http(s) schemes (blob:, mailto:, tel:, data:, ...). blob: URLs
|
package/dist/data/query.js
CHANGED
|
@@ -156,10 +156,7 @@ export function query(fn, name) {
|
|
|
156
156
|
}
|
|
157
157
|
let res = cached[1];
|
|
158
158
|
if (intent !== "preload") {
|
|
159
|
-
res =
|
|
160
|
-
"then" in cached[1]
|
|
161
|
-
? cached[1].then(handleResponse(false), handleResponse(true))
|
|
162
|
-
: handleResponse(false)(cached[1]);
|
|
159
|
+
res = settle(res);
|
|
163
160
|
!isServer && intent === "navigate" && cached[4][1](cached[0]); // update version
|
|
164
161
|
}
|
|
165
162
|
inPreloadFn && "then" in res && res.catch(() => { });
|
|
@@ -225,12 +222,8 @@ export function query(fn, name) {
|
|
|
225
222
|
if (e && e.router.dataOnly)
|
|
226
223
|
return (e.router.data[key] = res);
|
|
227
224
|
}
|
|
228
|
-
if (intent !== "preload")
|
|
229
|
-
res =
|
|
230
|
-
"then" in res
|
|
231
|
-
? res.then(handleResponse(false), handleResponse(true))
|
|
232
|
-
: handleResponse(false)(res);
|
|
233
|
-
}
|
|
225
|
+
if (intent !== "preload")
|
|
226
|
+
res = settle(res);
|
|
234
227
|
inPreloadFn && "then" in res && res.catch(() => { });
|
|
235
228
|
// serialize on server
|
|
236
229
|
if (isServer &&
|
|
@@ -241,6 +234,12 @@ export function query(fn, name) {
|
|
|
241
234
|
(!e || !e.serverOnly) && sharedConfig.context.serialize(key, res);
|
|
242
235
|
}
|
|
243
236
|
return res;
|
|
237
|
+
// a settled read: the response handling applied to the value or the promise
|
|
238
|
+
function settle(v) {
|
|
239
|
+
return "then" in v
|
|
240
|
+
? v.then(handleResponse(false), handleResponse(true))
|
|
241
|
+
: handleResponse(false)(v);
|
|
242
|
+
}
|
|
244
243
|
function handleResponse(error) {
|
|
245
244
|
return async (v) => {
|
|
246
245
|
let enveloped;
|
package/dist/fs.d.ts
CHANGED
|
@@ -35,7 +35,7 @@ export type FileRouteConfig<S extends string = string, T = unknown, F = undefine
|
|
|
35
35
|
* `matchFilters` are validated against the pattern's params, and their
|
|
36
36
|
* types (and any `search` schema) flow through the manifest into `paths`.
|
|
37
37
|
*/
|
|
38
|
-
export declare function defineFileRoute<S extends string, T = unknown, const F = DefinedRouteFilters<S>, Sch extends StandardSchemaV1<any, any> | undefined = undefined>(path: S, config
|
|
38
|
+
export declare function defineFileRoute<S extends string, T = unknown, const F = DefinedRouteFilters<S>, Sch extends StandardSchemaV1<any, any> | undefined = undefined>(path: S, config?: {
|
|
39
39
|
matchFilters?: (F & ValidFilters<F, S>) | undefined;
|
|
40
40
|
preload?: ((args: RoutePreloadFuncArgs<RouteParams<S>>) => T) | undefined;
|
|
41
41
|
/** Standard Schema validator for this route's search params; its input type flows into the typed path proxy. */
|
package/dist/fs.js
CHANGED
|
@@ -20,7 +20,7 @@ import * as server from "./fsServer.js";
|
|
|
20
20
|
* `matchFilters` are validated against the pattern's params, and their
|
|
21
21
|
* types (and any `search` schema) flow through the manifest into `paths`.
|
|
22
22
|
*/
|
|
23
|
-
export function defineFileRoute(path, config) {
|
|
23
|
+
export function defineFileRoute(path, config = {}) {
|
|
24
24
|
return config;
|
|
25
25
|
}
|
|
26
26
|
/**
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { getOwner, runWithOwner, createMemo, createRenderEffect, onCleanup, untrack, createContext, createSignal, useContext, NotReadyError,
|
|
1
|
+
import { getOwner, runWithOwner, createMemo, createRenderEffect, onCleanup, untrack, createContext, createSignal, useContext, NotReadyError, DEV, isPending, latest, createComponent, createRoot, Show, createEffect, sharedConfig, OBSERVE, onSettled, getObserver, $TRACK, action as action$1 } from 'solid-js';
|
|
2
2
|
import { registerElementClaim, delegateEvents, isServer, getRequestEvent, hasFlashCookie, clearFlashCookie, createComponent as createComponent$1, memo, dynamic, isServerFunction, getServerFunctionMetadata, getServerFunctionRPC, isResponseEnvelope, REVALIDATE_HEADER } from '@solidjs/web';
|
|
3
3
|
import { REDIRECT_HEADER, decodeRedirectHeaderValue, subscribeFlightData, decodeResponsePayload, parseServerFunctionActionUrl, createServerReference } from '@solidjs/web/server-functions';
|
|
4
4
|
|
|
@@ -72,13 +72,13 @@ function createMatcher(path, partial, matchFilters) {
|
|
|
72
72
|
path: len ? "" : "/",
|
|
73
73
|
params: {}
|
|
74
74
|
};
|
|
75
|
-
const
|
|
75
|
+
const filters = matchFilters;
|
|
76
76
|
for (let i = 0; i < len; i++) {
|
|
77
77
|
const segment = segments[i];
|
|
78
78
|
const dynamic = segment[0] === ":";
|
|
79
79
|
const locSegment = dynamic ? locSegments[i] : locSegments[i].toLowerCase();
|
|
80
80
|
const key = dynamic ? segment.slice(1) : segment.toLowerCase();
|
|
81
|
-
if (dynamic && matchSegment(locSegment,
|
|
81
|
+
if (dynamic && matchSegment(locSegment, filters?.[key])) {
|
|
82
82
|
match.params[key] = locSegment;
|
|
83
83
|
} else if (dynamic || !matchSegment(locSegment, key)) {
|
|
84
84
|
return null;
|
|
@@ -87,7 +87,7 @@ function createMatcher(path, partial, matchFilters) {
|
|
|
87
87
|
}
|
|
88
88
|
if (splat) {
|
|
89
89
|
const remainder = lenDiff ? locSegments.slice(-lenDiff).join("/") : "";
|
|
90
|
-
if (matchSegment(remainder,
|
|
90
|
+
if (matchSegment(remainder, filters?.[splat])) {
|
|
91
91
|
match.params[splat] = remainder;
|
|
92
92
|
} else {
|
|
93
93
|
return null;
|
|
@@ -96,21 +96,9 @@ function createMatcher(path, partial, matchFilters) {
|
|
|
96
96
|
return match;
|
|
97
97
|
};
|
|
98
98
|
}
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
return true;
|
|
103
|
-
} else if (typeof filter === "string") {
|
|
104
|
-
return isEqual(filter);
|
|
105
|
-
} else if (typeof filter === "function") {
|
|
106
|
-
return filter(input);
|
|
107
|
-
} else if (Array.isArray(filter)) {
|
|
108
|
-
return filter.some(isEqual);
|
|
109
|
-
} else if (filter instanceof RegExp) {
|
|
110
|
-
return filter.test(input);
|
|
111
|
-
}
|
|
112
|
-
return false;
|
|
113
|
-
}
|
|
99
|
+
|
|
100
|
+
// a string filter is the segment itself; anything else not listed never matches
|
|
101
|
+
const matchSegment = (input, filter) => filter === undefined || (typeof filter === "function" ? filter(input) : Array.isArray(filter) ? filter.includes(input) : filter instanceof RegExp ? filter.test(input) : filter === input);
|
|
114
102
|
function scoreRoute(route) {
|
|
115
103
|
const [pattern, splat] = route.pattern.split("/*", 2);
|
|
116
104
|
const segments = pattern.split("/").filter(Boolean);
|
|
@@ -340,7 +328,7 @@ function setupNativeEvents({
|
|
|
340
328
|
const target = svg ? a.target.baseVal : a.target;
|
|
341
329
|
if (target || !href && !a.hasAttribute("state")) return;
|
|
342
330
|
const rel = (a.getAttribute("rel") || "").split(/\s+/);
|
|
343
|
-
if (a.hasAttribute("download") || rel
|
|
331
|
+
if (a.hasAttribute("download") || rel.includes("external")) return;
|
|
344
332
|
const url = svg ? new URL(href, document.baseURI) : new URL(href);
|
|
345
333
|
// Skip non-http(s) schemes (blob:, mailto:, tel:, data:, ...). blob: URLs
|
|
346
334
|
// inherit the page origin, so the origin check below won't reject them. #382
|
|
@@ -514,8 +502,8 @@ function createPathsProxy(renderPath = p => p, base = "") {
|
|
|
514
502
|
};
|
|
515
503
|
return new Proxy(build, {
|
|
516
504
|
get(_, prop) {
|
|
517
|
-
if (prop === "toString") return () => toHref(pathname);
|
|
518
|
-
if (typeof prop === "symbol") return prop ===
|
|
505
|
+
if (prop === "toString" || prop === Symbol.toPrimitive) return () => toHref(pathname);
|
|
506
|
+
if (typeof prop === "symbol") return prop === HREF ? pathname || "/" : undefined;
|
|
519
507
|
return node(`${pathname}/${prop}`);
|
|
520
508
|
}
|
|
521
509
|
});
|
|
@@ -1023,9 +1011,7 @@ function createRoutes(routeDef, base = "") {
|
|
|
1023
1011
|
for (const expandedPath of expandOptionals(originalPath)) {
|
|
1024
1012
|
const path = joinPaths(base, expandedPath);
|
|
1025
1013
|
let pattern = isLeaf ? path : path.split("/*", 1)[0];
|
|
1026
|
-
pattern = pattern.split("/").map(s =>
|
|
1027
|
-
return s.startsWith(":") || s.startsWith("*") ? s : encodeSegment(s);
|
|
1028
|
-
}).join("/");
|
|
1014
|
+
pattern = pattern.split("/").map(s => /^[:*]/.test(s) ? s : encodeSegment(s)).join("/");
|
|
1029
1015
|
acc.push({
|
|
1030
1016
|
...shared,
|
|
1031
1017
|
originalPath,
|
|
@@ -1116,13 +1102,12 @@ function mergeParams(matches) {
|
|
|
1116
1102
|
return params;
|
|
1117
1103
|
}
|
|
1118
1104
|
function createLocation(path, state, queryWrapper) {
|
|
1119
|
-
const
|
|
1120
|
-
const url = createMemo((prev = origin) => {
|
|
1105
|
+
const url = createMemo((prev = new URL(mockBase)) => {
|
|
1121
1106
|
const path_ = path();
|
|
1122
1107
|
try {
|
|
1123
1108
|
// anchor rooted paths against the origin explicitly - a path with
|
|
1124
1109
|
// doubled leading slashes would otherwise parse as protocol-relative
|
|
1125
|
-
return new URL(path_[0] === "/" ? mockBase + path_ : path_,
|
|
1110
|
+
return new URL(path_[0] === "/" ? mockBase + path_ : path_, mockBase);
|
|
1126
1111
|
} catch (err) {
|
|
1127
1112
|
DEV && console.error(`Invalid path ${path_}`);
|
|
1128
1113
|
return prev;
|
|
@@ -1133,7 +1118,6 @@ function createLocation(path, state, queryWrapper) {
|
|
|
1133
1118
|
const pathname = createMemo(() => url().pathname);
|
|
1134
1119
|
const search = createMemo(() => url().search);
|
|
1135
1120
|
const hash = createMemo(() => url().hash);
|
|
1136
|
-
const key = () => "";
|
|
1137
1121
|
const queryFn = createMemo(() => extractSearchParams(url()));
|
|
1138
1122
|
return {
|
|
1139
1123
|
get pathname() {
|
|
@@ -1149,7 +1133,7 @@ function createLocation(path, state, queryWrapper) {
|
|
|
1149
1133
|
return state();
|
|
1150
1134
|
},
|
|
1151
1135
|
get key() {
|
|
1152
|
-
return
|
|
1136
|
+
return "";
|
|
1153
1137
|
},
|
|
1154
1138
|
query: queryWrapper ? queryWrapper(queryFn) : createMemoObject(queryFn)
|
|
1155
1139
|
};
|
|
@@ -1315,7 +1299,7 @@ function createRouterContext(integration, branches, getContext, options = {}) {
|
|
|
1315
1299
|
read = runWithOwner(routerOwner, () => createMemo(() => {
|
|
1316
1300
|
const result = resolveLazySubtree(record);
|
|
1317
1301
|
return result instanceof Promise ? result.then(() => undefined) : undefined;
|
|
1318
|
-
}, {
|
|
1302
|
+
}, DEV && {
|
|
1319
1303
|
name: "lazyRoutes"
|
|
1320
1304
|
}));
|
|
1321
1305
|
lazyReaders.set(record, read);
|
|
@@ -1348,7 +1332,7 @@ function createRouterContext(integration, branches, getContext, options = {}) {
|
|
|
1348
1332
|
}
|
|
1349
1333
|
}
|
|
1350
1334
|
return m;
|
|
1351
|
-
}, {
|
|
1335
|
+
}, DEV && {
|
|
1352
1336
|
name: "matches"
|
|
1353
1337
|
});
|
|
1354
1338
|
const routingPending = createMemo(() => isPending(() => {
|
|
@@ -1359,7 +1343,7 @@ function createRouterContext(integration, branches, getContext, options = {}) {
|
|
|
1359
1343
|
}
|
|
1360
1344
|
location.search;
|
|
1361
1345
|
location.hash;
|
|
1362
|
-
}), {
|
|
1346
|
+
}), DEV && {
|
|
1363
1347
|
name: "routingPending"
|
|
1364
1348
|
});
|
|
1365
1349
|
const isRouting = () => routingPending() || isPending(source);
|
|
@@ -1565,11 +1549,11 @@ function createRouterContext(integration, branches, getContext, options = {}) {
|
|
|
1565
1549
|
route,
|
|
1566
1550
|
params
|
|
1567
1551
|
} = next[match];
|
|
1568
|
-
route.component && route.component.preload && route.component.preload();
|
|
1569
1552
|
const {
|
|
1570
1553
|
preload,
|
|
1571
1554
|
component
|
|
1572
1555
|
} = route;
|
|
1556
|
+
component?.preload?.();
|
|
1573
1557
|
const now = current && current[match];
|
|
1574
1558
|
const unchanged = now && now.route.key === route.key && serverRouteArgsEqual(inputs(params, query, url.search, route), inputs(now.params, location.query, location.search, route));
|
|
1575
1559
|
inPreloadFn = true;
|
|
@@ -1633,7 +1617,7 @@ function createRouteContext(router, parent, outlet, match, matches = () => [matc
|
|
|
1633
1617
|
// its last valid value while this route is being torn down, so outgoing
|
|
1634
1618
|
// components and preloads never observe another route's params.
|
|
1635
1619
|
const params = wrapParams(() => mergeParams(matches()));
|
|
1636
|
-
component
|
|
1620
|
+
component?.preload?.();
|
|
1637
1621
|
inPreloadFn = true;
|
|
1638
1622
|
const data = preload ? preload({
|
|
1639
1623
|
params,
|
|
@@ -1760,9 +1744,7 @@ function Routes(props) {
|
|
|
1760
1744
|
next[i] = prev[i];
|
|
1761
1745
|
} else {
|
|
1762
1746
|
equal = false;
|
|
1763
|
-
|
|
1764
|
-
disposers[i]();
|
|
1765
|
-
}
|
|
1747
|
+
disposers[i]?.();
|
|
1766
1748
|
runWithOwner(owner, () => createRoot(dispose => {
|
|
1767
1749
|
disposers[i] = dispose;
|
|
1768
1750
|
const routeKey = nextMatch.route.key;
|
|
@@ -1851,13 +1833,14 @@ function bindEvent(target, type, handler) {
|
|
|
1851
1833
|
|
|
1852
1834
|
let depth;
|
|
1853
1835
|
function saveCurrentDepth() {
|
|
1854
|
-
|
|
1855
|
-
|
|
1856
|
-
|
|
1857
|
-
|
|
1836
|
+
const h = window.history;
|
|
1837
|
+
if (!h.state || h.state._depth == null) {
|
|
1838
|
+
h.replaceState({
|
|
1839
|
+
...h.state,
|
|
1840
|
+
_depth: h.length - 1
|
|
1858
1841
|
}, "");
|
|
1859
1842
|
}
|
|
1860
|
-
depth =
|
|
1843
|
+
depth = h.state?._depth ?? h.length - 1;
|
|
1861
1844
|
}
|
|
1862
1845
|
function keepDepth(state) {
|
|
1863
1846
|
return {
|
|
@@ -1901,11 +1884,10 @@ function scrollToHash(hash, fallbackTop) {
|
|
|
1901
1884
|
|
|
1902
1885
|
function browserHistory() {
|
|
1903
1886
|
const getSource = () => {
|
|
1904
|
-
const
|
|
1905
|
-
const state = window.history.state && window.history.state._depth && Object.keys(window.history.state).length === 1 ? undefined : window.history.state;
|
|
1887
|
+
const s = window.history.state;
|
|
1906
1888
|
return {
|
|
1907
|
-
value:
|
|
1908
|
-
state
|
|
1889
|
+
value: window.location.pathname + window.location.search + window.location.hash,
|
|
1890
|
+
state: s && s._depth && Object.keys(s).length === 1 ? undefined : s
|
|
1909
1891
|
};
|
|
1910
1892
|
};
|
|
1911
1893
|
const beforeLeave = {};
|
|
@@ -2133,7 +2115,7 @@ function createScrollRestoration() {
|
|
|
2133
2115
|
// reload/back_forward document loads land on an existing entry (a fresh
|
|
2134
2116
|
// navigation starts a new one and belongs at the top); the effect's
|
|
2135
2117
|
// initial run performs the restore after first render
|
|
2136
|
-
const [nav] = performance.getEntriesByType
|
|
2118
|
+
const [nav] = performance.getEntriesByType?.("navigation");
|
|
2137
2119
|
if (nav && nav.type !== "navigate") pending = depth();
|
|
2138
2120
|
}
|
|
2139
2121
|
};
|
|
@@ -2432,11 +2414,10 @@ function createRouter(config) {
|
|
|
2432
2414
|
}));
|
|
2433
2415
|
},
|
|
2434
2416
|
keysFor(url) {
|
|
2435
|
-
const pathname = typeof url === "string" ? new URL(url, mockBase).pathname : url[HREF];
|
|
2436
2417
|
const keys = [];
|
|
2437
2418
|
for (const {
|
|
2438
2419
|
route
|
|
2439
|
-
} of matchPath(
|
|
2420
|
+
} of matchPath(pathnameOf(url))) {
|
|
2440
2421
|
const key = serverRouteOf(route.component)?.call?.key;
|
|
2441
2422
|
typeof key === "string" && key && !keys.includes(key) && keys.push(key);
|
|
2442
2423
|
}
|
|
@@ -2751,7 +2732,7 @@ function query(fn, name) {
|
|
|
2751
2732
|
}
|
|
2752
2733
|
let res = cached[1];
|
|
2753
2734
|
if (intent !== "preload") {
|
|
2754
|
-
res =
|
|
2735
|
+
res = settle(res);
|
|
2755
2736
|
!isServer && intent === "navigate" && cached[4][1](cached[0]); // update version
|
|
2756
2737
|
}
|
|
2757
2738
|
inPreloadFn && "then" in res && res.catch(() => {});
|
|
@@ -2811,9 +2792,7 @@ function query(fn, name) {
|
|
|
2811
2792
|
const e = getRequestEvent();
|
|
2812
2793
|
if (e && e.router.dataOnly) return e.router.data[key] = res;
|
|
2813
2794
|
}
|
|
2814
|
-
if (intent !== "preload")
|
|
2815
|
-
res = "then" in res ? res.then(handleResponse(false), handleResponse(true)) : handleResponse(false)(res);
|
|
2816
|
-
}
|
|
2795
|
+
if (intent !== "preload") res = settle(res);
|
|
2817
2796
|
inPreloadFn && "then" in res && res.catch(() => {});
|
|
2818
2797
|
// serialize on server
|
|
2819
2798
|
if (isServer && sharedConfig.context && sharedConfig.context.async && !sharedConfig.context.noHydrate) {
|
|
@@ -2821,6 +2800,11 @@ function query(fn, name) {
|
|
|
2821
2800
|
(!e || !e.serverOnly) && sharedConfig.context.serialize(key, res);
|
|
2822
2801
|
}
|
|
2823
2802
|
return res;
|
|
2803
|
+
|
|
2804
|
+
// a settled read: the response handling applied to the value or the promise
|
|
2805
|
+
function settle(v) {
|
|
2806
|
+
return "then" in v ? v.then(handleResponse(false), handleResponse(true)) : handleResponse(false)(v);
|
|
2807
|
+
}
|
|
2824
2808
|
function handleResponse(error) {
|
|
2825
2809
|
return async v => {
|
|
2826
2810
|
let enveloped;
|
|
@@ -2997,7 +2981,8 @@ const actions = /* #__PURE__ */new Map();
|
|
|
2997
2981
|
*/
|
|
2998
2982
|
function handleFormAction(evt, router, actionBase) {
|
|
2999
2983
|
if (evt.defaultPrevented) return;
|
|
3000
|
-
|
|
2984
|
+
const form = evt.target;
|
|
2985
|
+
let actionRef = evt.submitter && evt.submitter.hasAttribute("formaction") ? evt.submitter.getAttribute("formaction") : form.getAttribute("action");
|
|
3001
2986
|
if (!actionRef) return;
|
|
3002
2987
|
const serverAction = !actionRef.startsWith("https://action/");
|
|
3003
2988
|
if (serverAction) {
|
|
@@ -3006,7 +2991,7 @@ function handleFormAction(evt, router, actionBase) {
|
|
|
3006
2991
|
actionRef = router.parsePath(url.pathname + url.search);
|
|
3007
2992
|
if (!actionRef.startsWith(actionBase)) return;
|
|
3008
2993
|
}
|
|
3009
|
-
if (
|
|
2994
|
+
if (form.method.toUpperCase() !== "POST") throw new Error("Only POST forms are supported for Actions");
|
|
3010
2995
|
// A registry miss on a server-action url is a direct bind whose module
|
|
3011
2996
|
// never loaded client-side (server components): the url is self-describing
|
|
3012
2997
|
// (the id in the path, bound `?args` in the query), so a generic invocation
|
|
@@ -3017,11 +3002,11 @@ function handleFormAction(evt, router, actionBase) {
|
|
|
3017
3002
|
const handler = actions.get(actionRef) || serverAction && createServerFormAction(actionRef);
|
|
3018
3003
|
if (handler) {
|
|
3019
3004
|
evt.preventDefault();
|
|
3020
|
-
const data = new FormData(
|
|
3005
|
+
const data = new FormData(form, evt.submitter);
|
|
3021
3006
|
handler.call({
|
|
3022
3007
|
r: router,
|
|
3023
|
-
f:
|
|
3024
|
-
},
|
|
3008
|
+
f: form
|
|
3009
|
+
}, form.enctype === "multipart/form-data" ? data : new URLSearchParams(data));
|
|
3025
3010
|
}
|
|
3026
3011
|
}
|
|
3027
3012
|
|
|
@@ -3128,23 +3113,21 @@ function actionImpl(fn, options = {}) {
|
|
|
3128
3113
|
const runMutation = () => fn(...variables);
|
|
3129
3114
|
const run = action$1(async function* (context) {
|
|
3130
3115
|
context.optimistic?.();
|
|
3116
|
+
let value;
|
|
3117
|
+
let error = false;
|
|
3131
3118
|
try {
|
|
3132
|
-
|
|
3133
|
-
|
|
3134
|
-
|
|
3135
|
-
|
|
3136
|
-
value
|
|
3137
|
-
};
|
|
3138
|
-
} catch (error) {
|
|
3139
|
-
yield;
|
|
3140
|
-
return {
|
|
3141
|
-
error: true,
|
|
3142
|
-
value: error
|
|
3143
|
-
};
|
|
3119
|
+
value = await context.call();
|
|
3120
|
+
} catch (e) {
|
|
3121
|
+
value = e;
|
|
3122
|
+
error = true;
|
|
3144
3123
|
}
|
|
3124
|
+
const read = await readResponse(value, error);
|
|
3125
|
+
yield;
|
|
3126
|
+
// Apply inside the transition so the default revalidation's refetch and
|
|
3127
|
+
// the release of the caller's optimistic writes commit as one frame (#619).
|
|
3128
|
+
return applyResponse(read, router.navigatorFactory(), flightApplications !== flightApplicationsBefore);
|
|
3145
3129
|
});
|
|
3146
3130
|
form && setFormBusy(form, 1);
|
|
3147
|
-
let settled;
|
|
3148
3131
|
let response;
|
|
3149
3132
|
// The transport consumer is awaited before a single-flight mutation
|
|
3150
3133
|
// resolves, so a counter delta over the call tells whether this action's
|
|
@@ -3154,13 +3137,12 @@ function actionImpl(fn, options = {}) {
|
|
|
3154
3137
|
// which misses every response the server returned without flight data.
|
|
3155
3138
|
const flightApplicationsBefore = flightApplications;
|
|
3156
3139
|
try {
|
|
3157
|
-
|
|
3140
|
+
response = await settleActionResult(run({
|
|
3158
3141
|
call: runMutation,
|
|
3159
3142
|
optimistic: submitHooks.size ? () => {
|
|
3160
3143
|
for (const hook of submitHooks.values()) hook(...variables);
|
|
3161
3144
|
} : undefined
|
|
3162
3145
|
}));
|
|
3163
|
-
response = await handleResponse(settled.value, settled.error, router.navigatorFactory(), flightApplications !== flightApplicationsBefore);
|
|
3164
3146
|
} finally {
|
|
3165
3147
|
form && setFormBusy(form, -1);
|
|
3166
3148
|
}
|
|
@@ -3168,8 +3150,8 @@ function actionImpl(fn, options = {}) {
|
|
|
3168
3150
|
submission = {
|
|
3169
3151
|
input: variables,
|
|
3170
3152
|
url,
|
|
3171
|
-
result: response
|
|
3172
|
-
error: response
|
|
3153
|
+
result: response?.data,
|
|
3154
|
+
error: response?.error,
|
|
3173
3155
|
clear() {
|
|
3174
3156
|
router.submissions[1](entries => entries.filter(entry => entry !== submission));
|
|
3175
3157
|
},
|
|
@@ -3215,8 +3197,7 @@ function toAction(invoke, url, boundArgs = [], base = url, submitHooks = new Map
|
|
|
3215
3197
|
fn.with = function (...args) {
|
|
3216
3198
|
const uri = new URL(url, mockBase);
|
|
3217
3199
|
uri.searchParams.set("args", hashKey(args));
|
|
3218
|
-
|
|
3219
|
-
return next;
|
|
3200
|
+
return toAction(invoke, (uri.origin === "https://action" ? uri.origin : "") + uri.pathname + uri.search, [...boundArgs, ...args], base, submitHooks, settledHooks);
|
|
3220
3201
|
};
|
|
3221
3202
|
fn.onSubmit = function (hook) {
|
|
3222
3203
|
const id = Symbol("actionOnSubmitHook");
|
|
@@ -3335,8 +3316,10 @@ function applyResponseMetadata(metadata, navigate, flightData) {
|
|
|
3335
3316
|
cacheKeyOp(keys, entry => entry[0] = 0);
|
|
3336
3317
|
// set cache — and fan the payload out to other keyed stores (live query
|
|
3337
3318
|
// channels adopt delivered values instead of reconnecting)
|
|
3338
|
-
|
|
3339
|
-
|
|
3319
|
+
if (flightData) {
|
|
3320
|
+
Object.keys(flightData).forEach(k => query.set(k, flightData[k]));
|
|
3321
|
+
deliverFlightData(flightData);
|
|
3322
|
+
}
|
|
3340
3323
|
// trigger revalidation inside the same transition as the navigation, so
|
|
3341
3324
|
// the redirect commits atomically with fresh data: surviving consumers
|
|
3342
3325
|
// (shared layouts) the flight payload didn't seed refetch and hold the
|
|
@@ -3344,7 +3327,7 @@ function applyResponseMetadata(metadata, navigate, flightData) {
|
|
|
3344
3327
|
// are fresh again by now, so the sweep re-reads them from cache.
|
|
3345
3328
|
revalidate(keys, false);
|
|
3346
3329
|
}
|
|
3347
|
-
async function
|
|
3330
|
+
async function readResponse(response, error) {
|
|
3348
3331
|
let data;
|
|
3349
3332
|
let flightData;
|
|
3350
3333
|
let metadata;
|
|
@@ -3367,6 +3350,19 @@ async function handleResponse(response, error, navigate, metadataHandled) {
|
|
|
3367
3350
|
} else if (error) return {
|
|
3368
3351
|
error: response
|
|
3369
3352
|
};else data = response;
|
|
3353
|
+
return {
|
|
3354
|
+
data,
|
|
3355
|
+
flightData,
|
|
3356
|
+
metadata
|
|
3357
|
+
};
|
|
3358
|
+
}
|
|
3359
|
+
function applyResponse(read, navigate, metadataHandled) {
|
|
3360
|
+
if ("error" in read) return read;
|
|
3361
|
+
const {
|
|
3362
|
+
data,
|
|
3363
|
+
flightData,
|
|
3364
|
+
metadata
|
|
3365
|
+
} = read;
|
|
3370
3366
|
// The transport consumer applies metadata before returning a server
|
|
3371
3367
|
// function's unwrapped value. Do not treat that value as a second plain
|
|
3372
3368
|
// action response and invalidate the freshly seeded query cache again.
|
package/dist/paths.js
CHANGED
|
@@ -37,14 +37,10 @@ export function createPathsProxy(renderPath = p => p, base = "") {
|
|
|
37
37
|
};
|
|
38
38
|
return new Proxy(build, {
|
|
39
39
|
get(_, prop) {
|
|
40
|
-
if (prop === "toString")
|
|
40
|
+
if (prop === "toString" || prop === Symbol.toPrimitive)
|
|
41
41
|
return () => toHref(pathname);
|
|
42
42
|
if (typeof prop === "symbol")
|
|
43
|
-
return prop ===
|
|
44
|
-
? () => toHref(pathname)
|
|
45
|
-
: prop === HREF
|
|
46
|
-
? pathname || "/"
|
|
47
|
-
: undefined;
|
|
43
|
+
return prop === HREF ? pathname || "/" : undefined;
|
|
48
44
|
return node(`${pathname}/${prop}`);
|
|
49
45
|
}
|
|
50
46
|
});
|
package/dist/routers/factory.jsx
CHANGED
|
@@ -247,9 +247,8 @@ export function createRouter(config) {
|
|
|
247
247
|
}));
|
|
248
248
|
},
|
|
249
249
|
keysFor(url) {
|
|
250
|
-
const pathname = typeof url === "string" ? new URL(url, mockBase).pathname : url[HREF];
|
|
251
250
|
const keys = [];
|
|
252
|
-
for (const { route } of matchPath(
|
|
251
|
+
for (const { route } of matchPath(pathnameOf(url))) {
|
|
253
252
|
const key = serverRouteOf(route.component)?.call?.key;
|
|
254
253
|
typeof key === "string" && key && !keys.includes(key) && keys.push(key);
|
|
255
254
|
}
|
package/dist/routers/history.js
CHANGED
|
@@ -9,10 +9,11 @@ export function bindEvent(target, type, handler) {
|
|
|
9
9
|
// guard machinery itself lives behind the lazy `beforeLeave` slot.
|
|
10
10
|
let depth;
|
|
11
11
|
export function saveCurrentDepth() {
|
|
12
|
-
|
|
13
|
-
|
|
12
|
+
const h = window.history;
|
|
13
|
+
if (!h.state || h.state._depth == null) {
|
|
14
|
+
h.replaceState({ ...h.state, _depth: h.length - 1 }, "");
|
|
14
15
|
}
|
|
15
|
-
depth =
|
|
16
|
+
depth = h.state?._depth ?? h.length - 1;
|
|
16
17
|
}
|
|
17
18
|
function keepDepth(state) {
|
|
18
19
|
return {
|
|
@@ -50,15 +51,10 @@ function scrollToHash(hash, fallbackTop) {
|
|
|
50
51
|
}
|
|
51
52
|
export function browserHistory() {
|
|
52
53
|
const getSource = () => {
|
|
53
|
-
const
|
|
54
|
-
const state = window.history.state &&
|
|
55
|
-
window.history.state._depth &&
|
|
56
|
-
Object.keys(window.history.state).length === 1
|
|
57
|
-
? undefined
|
|
58
|
-
: window.history.state;
|
|
54
|
+
const s = window.history.state;
|
|
59
55
|
return {
|
|
60
|
-
value:
|
|
61
|
-
state
|
|
56
|
+
value: window.location.pathname + window.location.search + window.location.hash,
|
|
57
|
+
state: s && s._depth && Object.keys(s).length === 1 ? undefined : s
|
|
62
58
|
};
|
|
63
59
|
};
|
|
64
60
|
const beforeLeave = {};
|
|
@@ -105,8 +105,7 @@ export function createScrollRestoration() {
|
|
|
105
105
|
// reload/back_forward document loads land on an existing entry (a fresh
|
|
106
106
|
// navigation starts a new one and belongs at the top); the effect's
|
|
107
107
|
// initial run performs the restore after first render
|
|
108
|
-
const [nav] =
|
|
109
|
-
performance.getEntriesByType("navigation"));
|
|
108
|
+
const [nav] = performance.getEntriesByType?.("navigation");
|
|
110
109
|
if (nav && nav.type !== "navigate")
|
|
111
110
|
pending = depth();
|
|
112
111
|
}
|
package/dist/routing.js
CHANGED
|
@@ -391,9 +391,7 @@ export function createRoutes(routeDef, base = "") {
|
|
|
391
391
|
let pattern = isLeaf ? path : path.split("/*", 1)[0];
|
|
392
392
|
pattern = pattern
|
|
393
393
|
.split("/")
|
|
394
|
-
.map((s)
|
|
395
|
-
return s.startsWith(":") || s.startsWith("*") ? s : encodeSegment(s);
|
|
396
|
-
})
|
|
394
|
+
.map(s => (/^[:*]/.test(s) ? s : encodeSegment(s)))
|
|
397
395
|
.join("/");
|
|
398
396
|
acc.push({
|
|
399
397
|
...shared,
|
|
@@ -487,13 +485,12 @@ export function mergeParams(matches) {
|
|
|
487
485
|
return params;
|
|
488
486
|
}
|
|
489
487
|
function createLocation(path, state, queryWrapper) {
|
|
490
|
-
const
|
|
491
|
-
const url = createMemo((prev = origin) => {
|
|
488
|
+
const url = createMemo((prev = new URL(mockBase)) => {
|
|
492
489
|
const path_ = path();
|
|
493
490
|
try {
|
|
494
491
|
// anchor rooted paths against the origin explicitly - a path with
|
|
495
492
|
// doubled leading slashes would otherwise parse as protocol-relative
|
|
496
|
-
return new URL(path_[0] === "/" ? mockBase + path_ : path_,
|
|
493
|
+
return new URL(path_[0] === "/" ? mockBase + path_ : path_, mockBase);
|
|
497
494
|
}
|
|
498
495
|
catch (err) {
|
|
499
496
|
DEV && console.error(`Invalid path ${path_}`);
|
|
@@ -505,7 +502,6 @@ function createLocation(path, state, queryWrapper) {
|
|
|
505
502
|
const pathname = createMemo(() => url().pathname);
|
|
506
503
|
const search = createMemo(() => url().search);
|
|
507
504
|
const hash = createMemo(() => url().hash);
|
|
508
|
-
const key = () => "";
|
|
509
505
|
const queryFn = createMemo(() => extractSearchParams(url()));
|
|
510
506
|
return {
|
|
511
507
|
get pathname() {
|
|
@@ -521,7 +517,7 @@ function createLocation(path, state, queryWrapper) {
|
|
|
521
517
|
return state();
|
|
522
518
|
},
|
|
523
519
|
get key() {
|
|
524
|
-
return
|
|
520
|
+
return "";
|
|
525
521
|
},
|
|
526
522
|
query: queryWrapper ? queryWrapper(queryFn) : createMemoObject(queryFn)
|
|
527
523
|
};
|
|
@@ -660,7 +656,7 @@ export function createRouterContext(integration, branches, getContext, options =
|
|
|
660
656
|
read = runWithOwner(routerOwner, () => createMemo(() => {
|
|
661
657
|
const result = resolveLazySubtree(record);
|
|
662
658
|
return result instanceof Promise ? result.then(() => undefined) : undefined;
|
|
663
|
-
}, { name: "lazyRoutes" }));
|
|
659
|
+
}, DEV && { name: "lazyRoutes" }));
|
|
664
660
|
lazyReaders.set(record, read);
|
|
665
661
|
}
|
|
666
662
|
return read();
|
|
@@ -695,7 +691,7 @@ export function createRouterContext(integration, branches, getContext, options =
|
|
|
695
691
|
}
|
|
696
692
|
}
|
|
697
693
|
return m;
|
|
698
|
-
}, { name: "matches" });
|
|
694
|
+
}, DEV && { name: "matches" });
|
|
699
695
|
const routingPending = createMemo(() => isPending(() => {
|
|
700
696
|
try {
|
|
701
697
|
matches();
|
|
@@ -706,7 +702,7 @@ export function createRouterContext(integration, branches, getContext, options =
|
|
|
706
702
|
}
|
|
707
703
|
location.search;
|
|
708
704
|
location.hash;
|
|
709
|
-
}), { name: "routingPending" });
|
|
705
|
+
}), DEV && { name: "routingPending" });
|
|
710
706
|
const isRouting = () => routingPending() || isPending(source);
|
|
711
707
|
const transitionIntent = () => {
|
|
712
708
|
if (!isPending(source))
|
|
@@ -912,10 +908,8 @@ export function createRouterContext(integration, branches, getContext, options =
|
|
|
912
908
|
preloadIntent = "preload";
|
|
913
909
|
for (let match in next) {
|
|
914
910
|
const { route, params } = next[match];
|
|
915
|
-
route.component &&
|
|
916
|
-
route.component.preload &&
|
|
917
|
-
route.component.preload();
|
|
918
911
|
const { preload, component } = route;
|
|
912
|
+
component?.preload?.();
|
|
919
913
|
const now = current && current[match];
|
|
920
914
|
const unchanged = now &&
|
|
921
915
|
now.route.key === route.key &&
|
|
@@ -978,9 +972,7 @@ export function createRouteContext(router, parent, outlet, match, matches = () =
|
|
|
978
972
|
// its last valid value while this route is being torn down, so outgoing
|
|
979
973
|
// components and preloads never observe another route's params.
|
|
980
974
|
const params = wrapParams(() => mergeParams(matches()));
|
|
981
|
-
component
|
|
982
|
-
component.preload &&
|
|
983
|
-
component.preload();
|
|
975
|
+
component?.preload?.();
|
|
984
976
|
inPreloadFn = true;
|
|
985
977
|
const data = preload
|
|
986
978
|
? preload({ params, location, intent: router.intent?.() || "initial" })
|
package/dist/utils.js
CHANGED
|
@@ -78,13 +78,13 @@ export function createMatcher(path, partial, matchFilters) {
|
|
|
78
78
|
path: len ? "" : "/",
|
|
79
79
|
params: {}
|
|
80
80
|
};
|
|
81
|
-
const
|
|
81
|
+
const filters = matchFilters;
|
|
82
82
|
for (let i = 0; i < len; i++) {
|
|
83
83
|
const segment = segments[i];
|
|
84
84
|
const dynamic = segment[0] === ":";
|
|
85
85
|
const locSegment = dynamic ? locSegments[i] : locSegments[i].toLowerCase();
|
|
86
86
|
const key = dynamic ? segment.slice(1) : segment.toLowerCase();
|
|
87
|
-
if (dynamic && matchSegment(locSegment,
|
|
87
|
+
if (dynamic && matchSegment(locSegment, filters?.[key])) {
|
|
88
88
|
match.params[key] = locSegment;
|
|
89
89
|
}
|
|
90
90
|
else if (dynamic || !matchSegment(locSegment, key)) {
|
|
@@ -94,7 +94,7 @@ export function createMatcher(path, partial, matchFilters) {
|
|
|
94
94
|
}
|
|
95
95
|
if (splat) {
|
|
96
96
|
const remainder = lenDiff ? locSegments.slice(-lenDiff).join("/") : "";
|
|
97
|
-
if (matchSegment(remainder,
|
|
97
|
+
if (matchSegment(remainder, filters?.[splat])) {
|
|
98
98
|
match.params[splat] = remainder;
|
|
99
99
|
}
|
|
100
100
|
else {
|
|
@@ -104,25 +104,15 @@ export function createMatcher(path, partial, matchFilters) {
|
|
|
104
104
|
return match;
|
|
105
105
|
};
|
|
106
106
|
}
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
return filter(input);
|
|
117
|
-
}
|
|
118
|
-
else if (Array.isArray(filter)) {
|
|
119
|
-
return filter.some(isEqual);
|
|
120
|
-
}
|
|
121
|
-
else if (filter instanceof RegExp) {
|
|
122
|
-
return filter.test(input);
|
|
123
|
-
}
|
|
124
|
-
return false;
|
|
125
|
-
}
|
|
107
|
+
// a string filter is the segment itself; anything else not listed never matches
|
|
108
|
+
const matchSegment = (input, filter) => filter === undefined ||
|
|
109
|
+
(typeof filter === "function"
|
|
110
|
+
? filter(input)
|
|
111
|
+
: Array.isArray(filter)
|
|
112
|
+
? filter.includes(input)
|
|
113
|
+
: filter instanceof RegExp
|
|
114
|
+
? filter.test(input)
|
|
115
|
+
: filter === input);
|
|
126
116
|
export function scoreRoute(route) {
|
|
127
117
|
const [pattern, splat] = route.pattern.split("/*", 2);
|
|
128
118
|
const segments = pattern.split("/").filter(Boolean);
|
package/package.json
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
"Ryan Turnquist"
|
|
7
7
|
],
|
|
8
8
|
"license": "MIT",
|
|
9
|
-
"version": "2.0.0-next.
|
|
9
|
+
"version": "2.0.0-next.31",
|
|
10
10
|
"homepage": "https://github.com/solidjs/solid-router#readme",
|
|
11
11
|
"repository": {
|
|
12
12
|
"type": "git",
|
|
@@ -38,22 +38,22 @@
|
|
|
38
38
|
"@rollup/plugin-node-resolve": "15.3.0",
|
|
39
39
|
"@rollup/plugin-terser": "0.4.4",
|
|
40
40
|
"@solidjs/vite-plugin": "3.0.0-next.35",
|
|
41
|
-
"@solidjs/web": "^2.0.0-rc.
|
|
41
|
+
"@solidjs/web": "^2.0.0-rc.11",
|
|
42
42
|
"@types/jest": "^29.5.14",
|
|
43
43
|
"@types/node": "^22.10.0",
|
|
44
44
|
"babel-preset-solid": "^2.0.0-rc.2",
|
|
45
45
|
"jsdom": "^25.0.1",
|
|
46
46
|
"prettier": "^3.4.1",
|
|
47
47
|
"rollup": "^4.27.4",
|
|
48
|
-
"solid-js": "^2.0.0-rc.
|
|
48
|
+
"solid-js": "^2.0.0-rc.11",
|
|
49
49
|
"typescript": "^5.7.2",
|
|
50
50
|
"vite": "^8.2.2",
|
|
51
51
|
"vitest": "^4.1.11"
|
|
52
52
|
},
|
|
53
53
|
"peerDependencies": {
|
|
54
|
-
"@solidjs/web": "^2.0.0-rc.
|
|
54
|
+
"@solidjs/web": "^2.0.0-rc.10",
|
|
55
55
|
"filesystem-routing": ">=0.4.0",
|
|
56
|
-
"solid-js": "^2.0.0-rc.
|
|
56
|
+
"solid-js": "^2.0.0-rc.10"
|
|
57
57
|
},
|
|
58
58
|
"peerDependenciesMeta": {
|
|
59
59
|
"filesystem-routing": {
|