@solidjs/router 2.0.0-next.22 → 2.0.0-next.24
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 +2 -0
- package/dist/fs.d.ts +6 -6
- package/dist/index.js +71 -23
- package/dist/routers/factory.d.ts +10 -10
- package/dist/routers/factory.jsx +70 -26
- package/dist/routing.js +5 -4
- package/dist/types.d.ts +7 -7
- package/package.json +5 -5
package/README.md
CHANGED
|
@@ -750,6 +750,8 @@ const isRouting = useIsRouting();
|
|
|
750
750
|
return <div classList={{ "grey-out": isRouting() }}>...</div>;
|
|
751
751
|
```
|
|
752
752
|
|
|
753
|
+
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.navigations()` and `feedback().navigations` list them; nothing of this exists in production builds.
|
|
754
|
+
|
|
753
755
|
### useMatch
|
|
754
756
|
|
|
755
757
|
Tests a path *pattern you supply* against the current location; returns a memo of match information or `undefined`. It never consults the route tree — the pattern doesn't have to correspond to a defined route. The match's `params` are typed from the pattern, and a typed path node works too (a concrete URL — useful for "am I here" checks):
|
package/dist/fs.d.ts
CHANGED
|
@@ -12,8 +12,8 @@ export type FileRouteConfig<S extends string = string, T = unknown, F = undefine
|
|
|
12
12
|
}) & ([Sch] extends [undefined] ? {} : {
|
|
13
13
|
search: Sch;
|
|
14
14
|
}) & {
|
|
15
|
-
preload?: RoutePreloadFunc<T
|
|
16
|
-
info?: RouteInfo;
|
|
15
|
+
preload?: RoutePreloadFunc<T> | undefined;
|
|
16
|
+
info?: RouteInfo | undefined;
|
|
17
17
|
};
|
|
18
18
|
/**
|
|
19
19
|
* Identity helper for a route file's `route` export that types `preload`'s
|
|
@@ -34,11 +34,11 @@ export type FileRouteConfig<S extends string = string, T = unknown, F = undefine
|
|
|
34
34
|
* types (and any `search` schema) flow through the manifest into `paths`.
|
|
35
35
|
*/
|
|
36
36
|
export declare function defineFileRoute<S extends string, T = unknown, const F = DefinedRouteFilters<S>, Sch extends StandardSchemaV1<any, any> | undefined = undefined>(path: S, config: {
|
|
37
|
-
matchFilters?: F & ValidFilters<F, S
|
|
38
|
-
preload?: (args: RoutePreloadFuncArgs<RouteParams<S>>) => T;
|
|
37
|
+
matchFilters?: (F & ValidFilters<F, S>) | undefined;
|
|
38
|
+
preload?: ((args: RoutePreloadFuncArgs<RouteParams<S>>) => T) | undefined;
|
|
39
39
|
/** Standard Schema validator for this route's search params; its input type flows into the typed path proxy. */
|
|
40
40
|
search?: Sch;
|
|
41
|
-
info?: RouteInfo;
|
|
41
|
+
info?: RouteInfo | undefined;
|
|
42
42
|
}): FileRouteConfig<S, T, F, Sch>;
|
|
43
43
|
/** A code-split module ref: delivered as a dynamic import. */
|
|
44
44
|
export interface FileRouteLazyRef<M = Record<string, unknown>> {
|
|
@@ -47,7 +47,7 @@ export interface FileRouteLazyRef<M = Record<string, unknown>> {
|
|
|
47
47
|
}
|
|
48
48
|
/** An eager module ref: its picked exports are imported statically. */
|
|
49
49
|
export interface FileRouteEagerRef<M = Record<string, unknown>> {
|
|
50
|
-
src?: string;
|
|
50
|
+
src?: string | undefined;
|
|
51
51
|
require(): M;
|
|
52
52
|
}
|
|
53
53
|
/** The shape of a nested route-manifest entry the adapter consumes. */
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { getOwner, runWithOwner, createMemo, createRenderEffect, onCleanup, untrack, createContext, createSignal, useContext, NotReadyError, isPending, DEV, latest, createComponent, createRoot, Show, createEffect, sharedConfig, onSettled, getObserver, $TRACK, action as action$1 } from 'solid-js';
|
|
1
|
+
import { getOwner, runWithOwner, createMemo, createRenderEffect, onCleanup, untrack, createContext, createSignal, useContext, NotReadyError, isPending, DEV, 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, isServerFunction, getServerFunctionMetadata, getServerFunctionRPC, isResponseEnvelope, REVALIDATE_HEADER } from '@solidjs/web';
|
|
3
3
|
import { subscribeFlightData, decodeRedirectHeaderValue, REDIRECT_HEADER, decodeResponsePayload, parseServerFunctionUrl, createServerReference } from '@solidjs/web/server-functions';
|
|
4
4
|
import { decodeFlashCookie } from '@solidjs/web/server-functions/server';
|
|
@@ -971,7 +971,8 @@ function createBranches(routeDef, base = "", stack = [], branches = []) {
|
|
|
971
971
|
for (let i = 0, len = routeDefs.length; i < len; i++) {
|
|
972
972
|
const def = routeDefs[i];
|
|
973
973
|
if (def && typeof def === "object") {
|
|
974
|
-
|
|
974
|
+
// absent and explicitly `undefined` paths are the same pathless route
|
|
975
|
+
if (def.path === undefined) def.path = "";
|
|
975
976
|
const routes = createRoutes(def, base);
|
|
976
977
|
for (const route of routes) {
|
|
977
978
|
stack.push(route);
|
|
@@ -1220,6 +1221,8 @@ function createRouterContext(integration, branches, getContext, options = {}) {
|
|
|
1220
1221
|
read = runWithOwner(routerOwner, () => createMemo(() => {
|
|
1221
1222
|
const result = resolveLazySubtree(record);
|
|
1222
1223
|
return result instanceof Promise ? result.then(() => undefined) : undefined;
|
|
1224
|
+
}, {
|
|
1225
|
+
name: "lazyRoutes"
|
|
1223
1226
|
}));
|
|
1224
1227
|
lazyReaders.set(record, read);
|
|
1225
1228
|
}
|
|
@@ -1251,6 +1254,8 @@ function createRouterContext(integration, branches, getContext, options = {}) {
|
|
|
1251
1254
|
}
|
|
1252
1255
|
}
|
|
1253
1256
|
return m;
|
|
1257
|
+
}, {
|
|
1258
|
+
name: "matches"
|
|
1254
1259
|
});
|
|
1255
1260
|
const routingPending = createMemo(() => isPending(() => {
|
|
1256
1261
|
try {
|
|
@@ -1260,7 +1265,9 @@ function createRouterContext(integration, branches, getContext, options = {}) {
|
|
|
1260
1265
|
}
|
|
1261
1266
|
location.search;
|
|
1262
1267
|
location.hash;
|
|
1263
|
-
})
|
|
1268
|
+
}), {
|
|
1269
|
+
name: "routingPending"
|
|
1270
|
+
});
|
|
1264
1271
|
const isRouting = () => routingPending() || isPending(source);
|
|
1265
1272
|
const transitionIntent = () => {
|
|
1266
1273
|
if (!isPending(source)) return;
|
|
@@ -2022,32 +2029,74 @@ function defineRoutes(routes) {
|
|
|
2022
2029
|
function defineRoute(route) {
|
|
2023
2030
|
return route;
|
|
2024
2031
|
}
|
|
2032
|
+
/**
|
|
2033
|
+
* What one location write is, for solid's observe tier: the parametrized
|
|
2034
|
+
* route it heads to, the params, where it came from, and — when the write is
|
|
2035
|
+
* the router chasing a redirect while the previous target is still pending —
|
|
2036
|
+
* which hop of that navigation it is. The engine times the navigation from
|
|
2037
|
+
* this declaration (or from the user event enclosing it) until its writes
|
|
2038
|
+
* are through, and names holds and re-runs after it.
|
|
2039
|
+
*
|
|
2040
|
+
* `name` and `params` are getters: the engine reads them when the navigation
|
|
2041
|
+
* settles, not when it starts, so a lazy route subtree that loaded during the
|
|
2042
|
+
* hold names the exact route it resolved to rather than its placeholder.
|
|
2043
|
+
* Redirect depth comes from `_navigation` (1 = a navigation, n = its
|
|
2044
|
+
* (n - 1)th redirect hop, -1 = the browser moved: back/forward, hash).
|
|
2045
|
+
*/
|
|
2046
|
+
function describeNavigation(match, next, from) {
|
|
2047
|
+
const pathname = new URL(next.value, mockBase).pathname;
|
|
2048
|
+
const matches = () => untrack(() => match(pathname));
|
|
2049
|
+
const ref = {
|
|
2050
|
+
kind: "navigation",
|
|
2051
|
+
to: next.value,
|
|
2052
|
+
from,
|
|
2053
|
+
get name() {
|
|
2054
|
+
const m = matches();
|
|
2055
|
+
return m.length ? m[m.length - 1].route.pattern || "/" : pathname;
|
|
2056
|
+
},
|
|
2057
|
+
get params() {
|
|
2058
|
+
const m = matches();
|
|
2059
|
+
return m.length ? mergeParams(m) : undefined;
|
|
2060
|
+
}
|
|
2061
|
+
};
|
|
2062
|
+
if (next._navigation !== undefined && next._navigation > 1) ref.redirect = next._navigation - 1;
|
|
2063
|
+
return ref;
|
|
2064
|
+
}
|
|
2065
|
+
|
|
2025
2066
|
/** Wraps a history adapter in the integration signal the router core consumes. Must run under a reactive owner. */
|
|
2026
|
-
function createIntegration(history) {
|
|
2067
|
+
function createIntegration(history, match) {
|
|
2027
2068
|
let committing = false;
|
|
2028
2069
|
const wrap = value => typeof value === "string" ? {
|
|
2029
2070
|
value
|
|
2030
2071
|
} : value;
|
|
2031
2072
|
const [read, write] = createSignal(wrap(history.get()), {
|
|
2032
2073
|
equals: (a, b) => a.value === b.value && a.state === b.state && a._navigation === b._navigation,
|
|
2033
|
-
ownedWrite: true
|
|
2074
|
+
ownedWrite: true,
|
|
2075
|
+
name: "location"
|
|
2034
2076
|
});
|
|
2035
2077
|
const signal = [read, next => {
|
|
2036
2078
|
if (sharedConfig.registry && !sharedConfig.done) sharedConfig.done = true;
|
|
2037
|
-
|
|
2038
|
-
|
|
2039
|
-
|
|
2040
|
-
|
|
2041
|
-
|
|
2042
|
-
|
|
2043
|
-
|
|
2044
|
-
|
|
2045
|
-
|
|
2046
|
-
|
|
2047
|
-
|
|
2048
|
-
|
|
2049
|
-
|
|
2050
|
-
|
|
2079
|
+
const commit = () => {
|
|
2080
|
+
write(next);
|
|
2081
|
+
if (next._navigation && next._navigation > 0) {
|
|
2082
|
+
// Register out of band so a destination error boundary replacing the
|
|
2083
|
+
// Router subtree cannot suppress the winning history commit.
|
|
2084
|
+
runWithOwner(null, () => onSettled(() => {
|
|
2085
|
+
if (read() !== next) return;
|
|
2086
|
+
committing = true;
|
|
2087
|
+
try {
|
|
2088
|
+
history.set(next);
|
|
2089
|
+
} finally {
|
|
2090
|
+
committing = false;
|
|
2091
|
+
}
|
|
2092
|
+
}));
|
|
2093
|
+
}
|
|
2094
|
+
};
|
|
2095
|
+
// Every client location write passes here — navigate(), a redirect hop,
|
|
2096
|
+
// the browser's own back/forward — so this is the one place the
|
|
2097
|
+
// navigation is declared. `read()` still holds the committed location
|
|
2098
|
+
// while a navigation is pending, which is the `from` a hop wants too.
|
|
2099
|
+
OBSERVE ? OBSERVE.attribution.withOrigin(describeNavigation(match, next, untrack(read).value), commit) : commit();
|
|
2051
2100
|
}];
|
|
2052
2101
|
history.init && onCleanup(history.init((value = history.get()) => {
|
|
2053
2102
|
if (committing) return;
|
|
@@ -2103,6 +2152,7 @@ function createRouter(config) {
|
|
|
2103
2152
|
return compiled;
|
|
2104
2153
|
};
|
|
2105
2154
|
const renderPath = config.history && config.history.utils && config.history.utils.renderPath || undefined;
|
|
2155
|
+
const matchPath = pathname => getRouteMatches(branches(), config.transformUrl ? config.transformUrl(pathname) : pathname);
|
|
2106
2156
|
function RouterComponent(props) {
|
|
2107
2157
|
// One router per app: the session (location, history, delegation, link
|
|
2108
2158
|
// claims, preloading) has a single owner, and a second instance would
|
|
@@ -2119,7 +2169,7 @@ function createRouter(config) {
|
|
|
2119
2169
|
restoration = createScrollRestoration();
|
|
2120
2170
|
history = withScrollRestoration(history || browserHistory(), restoration);
|
|
2121
2171
|
}
|
|
2122
|
-
const integration = isServer ? staticIntegration(props.url, config.history && config.history.utils) : createIntegration(history || browserHistory());
|
|
2172
|
+
const integration = isServer ? staticIntegration(props.url, config.history && config.history.utils) : createIntegration(history || browserHistory(), matchPath);
|
|
2123
2173
|
let context;
|
|
2124
2174
|
const routerState = createRouterContext(integration, branches, () => context, {
|
|
2125
2175
|
base: basePath,
|
|
@@ -2160,9 +2210,7 @@ function createRouter(config) {
|
|
|
2160
2210
|
routes: config.routes,
|
|
2161
2211
|
config,
|
|
2162
2212
|
match(url) {
|
|
2163
|
-
|
|
2164
|
-
const pathname = config.transformUrl ? config.transformUrl(u.pathname) : u.pathname;
|
|
2165
|
-
return getRouteMatches(branches(), pathname).map(({
|
|
2213
|
+
return matchPath(new URL(url, mockBase).pathname).map(({
|
|
2166
2214
|
route,
|
|
2167
2215
|
path,
|
|
2168
2216
|
params
|
|
@@ -32,9 +32,9 @@ export type DefinedRoute<S = undefined, T = unknown, F = undefined, C = undefine
|
|
|
32
32
|
}) & ([Sch] extends [undefined] ? {} : {
|
|
33
33
|
search: Sch;
|
|
34
34
|
}) & {
|
|
35
|
-
component?: RouteSectionComponent<T
|
|
36
|
-
preload?: RoutePreloadFunc<T
|
|
37
|
-
info?: RouteInfo;
|
|
35
|
+
component?: RouteSectionComponent<T> | undefined;
|
|
36
|
+
preload?: RoutePreloadFunc<T> | undefined;
|
|
37
|
+
info?: RouteInfo | undefined;
|
|
38
38
|
};
|
|
39
39
|
/**
|
|
40
40
|
* Identity helper that types a single route from its own `path` pattern:
|
|
@@ -49,20 +49,20 @@ export type DefinedRoute<S = undefined, T = unknown, F = undefined, C = undefine
|
|
|
49
49
|
*/
|
|
50
50
|
export declare function defineRoute<const S extends string | readonly string[], T = unknown, const F = DefinedRouteFilters<S>, const C extends RouteChildren | undefined = RouteChildren | undefined, Sch extends StandardSchemaV1<any, any> | undefined = undefined>(route: {
|
|
51
51
|
path: S;
|
|
52
|
-
matchFilters?: F & ValidFilters<F, S
|
|
53
|
-
preload?: (args: RoutePreloadFuncArgs<RouteParams<S>>) => T;
|
|
54
|
-
component?: DefinedRouteComponent<T, RouteParams<S
|
|
52
|
+
matchFilters?: (F & ValidFilters<F, S>) | undefined;
|
|
53
|
+
preload?: ((args: RoutePreloadFuncArgs<RouteParams<S>>) => T) | undefined;
|
|
54
|
+
component?: DefinedRouteComponent<T, RouteParams<S>> | undefined;
|
|
55
55
|
children?: C;
|
|
56
56
|
/** Standard Schema validator for this route's search params; its input type flows into the typed path proxy. */
|
|
57
57
|
search?: Sch;
|
|
58
|
-
info?: RouteInfo;
|
|
58
|
+
info?: RouteInfo | undefined;
|
|
59
59
|
}): DefinedRoute<S, T, F, C, Sch>;
|
|
60
60
|
export declare function defineRoute<T = unknown, const C extends RouteChildren | undefined = RouteChildren | undefined, Sch extends StandardSchemaV1<any, any> | undefined = undefined>(route: {
|
|
61
|
-
preload?: (args: RoutePreloadFuncArgs) => T;
|
|
62
|
-
component?: DefinedRouteComponent<T, Params
|
|
61
|
+
preload?: ((args: RoutePreloadFuncArgs) => T) | undefined;
|
|
62
|
+
component?: DefinedRouteComponent<T, Params> | undefined;
|
|
63
63
|
children?: C;
|
|
64
64
|
search?: Sch;
|
|
65
|
-
info?: RouteInfo;
|
|
65
|
+
info?: RouteInfo | undefined;
|
|
66
66
|
}): DefinedRoute<undefined, T, undefined, C, Sch>;
|
|
67
67
|
export interface RouterConfig<R extends readonly RouteDefinition[] = RouteDefinition[]> {
|
|
68
68
|
/** The route tree. Immutable per instance — it is the source of truth for matching *and* types. */
|
package/dist/routers/factory.jsx
CHANGED
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
/*@refresh skip*/
|
|
2
2
|
import { createSignal, getOwner, onCleanup, onSettled, runWithOwner, sharedConfig, untrack } from "solid-js";
|
|
3
|
-
// standalone
|
|
4
|
-
//
|
|
5
|
-
|
|
3
|
+
// standalone imports: `DEV` is undefined in solid's production build and
|
|
4
|
+
// `OBSERVE` outside its observe/dev builds, so app bundlers fold the
|
|
5
|
+
// `DEV &&` diagnostics and the `OBSERVE &&` attribution out of shipped bundles
|
|
6
|
+
import { DEV, OBSERVE } from "solid-js";
|
|
6
7
|
import { getRequestEvent, isServer } from "@solidjs/web";
|
|
7
8
|
import { setupLinkClaims } from "../claims.js";
|
|
8
9
|
import { setupNativeEvents } from "../data/events.js";
|
|
9
10
|
import { createPathsProxy } from "../paths.js";
|
|
10
|
-
import { createBranches, createRouterContext, getRouteMatches, registerFlightRouter, RouterContextObj, trackLazySubtrees, useOptionalContext } from "../routing.js";
|
|
11
|
+
import { createBranches, createRouterContext, getRouteMatches, mergeParams, registerFlightRouter, RouterContextObj, trackLazySubtrees, useOptionalContext } from "../routing.js";
|
|
11
12
|
import { mockBase } from "../utils.js";
|
|
12
13
|
import { Root, Routes } from "./components.jsx";
|
|
13
14
|
import { browserHistory } from "./history.js";
|
|
@@ -25,35 +26,79 @@ export function defineRoutes(routes) {
|
|
|
25
26
|
export function defineRoute(route) {
|
|
26
27
|
return route;
|
|
27
28
|
}
|
|
29
|
+
/**
|
|
30
|
+
* What one location write is, for solid's observe tier: the parametrized
|
|
31
|
+
* route it heads to, the params, where it came from, and — when the write is
|
|
32
|
+
* the router chasing a redirect while the previous target is still pending —
|
|
33
|
+
* which hop of that navigation it is. The engine times the navigation from
|
|
34
|
+
* this declaration (or from the user event enclosing it) until its writes
|
|
35
|
+
* are through, and names holds and re-runs after it.
|
|
36
|
+
*
|
|
37
|
+
* `name` and `params` are getters: the engine reads them when the navigation
|
|
38
|
+
* settles, not when it starts, so a lazy route subtree that loaded during the
|
|
39
|
+
* hold names the exact route it resolved to rather than its placeholder.
|
|
40
|
+
* Redirect depth comes from `_navigation` (1 = a navigation, n = its
|
|
41
|
+
* (n - 1)th redirect hop, -1 = the browser moved: back/forward, hash).
|
|
42
|
+
*/
|
|
43
|
+
function describeNavigation(match, next, from) {
|
|
44
|
+
const pathname = new URL(next.value, mockBase).pathname;
|
|
45
|
+
const matches = () => untrack(() => match(pathname));
|
|
46
|
+
const ref = {
|
|
47
|
+
kind: "navigation",
|
|
48
|
+
to: next.value,
|
|
49
|
+
from,
|
|
50
|
+
get name() {
|
|
51
|
+
const m = matches();
|
|
52
|
+
return m.length ? m[m.length - 1].route.pattern || "/" : pathname;
|
|
53
|
+
},
|
|
54
|
+
get params() {
|
|
55
|
+
const m = matches();
|
|
56
|
+
return m.length ? mergeParams(m) : undefined;
|
|
57
|
+
}
|
|
58
|
+
};
|
|
59
|
+
if (next._navigation !== undefined && next._navigation > 1)
|
|
60
|
+
ref.redirect = next._navigation - 1;
|
|
61
|
+
return ref;
|
|
62
|
+
}
|
|
28
63
|
/** Wraps a history adapter in the integration signal the router core consumes. Must run under a reactive owner. */
|
|
29
|
-
function createIntegration(history) {
|
|
64
|
+
function createIntegration(history, match) {
|
|
30
65
|
let committing = false;
|
|
31
66
|
const wrap = (value) => (typeof value === "string" ? { value } : value);
|
|
32
67
|
const [read, write] = createSignal(wrap(history.get()), {
|
|
33
68
|
equals: (a, b) => a.value === b.value && a.state === b.state && a._navigation === b._navigation,
|
|
34
|
-
ownedWrite: true
|
|
69
|
+
ownedWrite: true,
|
|
70
|
+
name: "location"
|
|
35
71
|
});
|
|
36
72
|
const signal = [
|
|
37
73
|
read,
|
|
38
74
|
(next) => {
|
|
39
75
|
if (sharedConfig.registry && !sharedConfig.done)
|
|
40
76
|
sharedConfig.done = true;
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
77
|
+
const commit = () => {
|
|
78
|
+
write(next);
|
|
79
|
+
if (next._navigation && next._navigation > 0) {
|
|
80
|
+
// Register out of band so a destination error boundary replacing the
|
|
81
|
+
// Router subtree cannot suppress the winning history commit.
|
|
82
|
+
runWithOwner(null, () => onSettled(() => {
|
|
83
|
+
if (read() !== next)
|
|
84
|
+
return;
|
|
85
|
+
committing = true;
|
|
86
|
+
try {
|
|
87
|
+
history.set(next);
|
|
88
|
+
}
|
|
89
|
+
finally {
|
|
90
|
+
committing = false;
|
|
91
|
+
}
|
|
92
|
+
}));
|
|
93
|
+
}
|
|
94
|
+
};
|
|
95
|
+
// Every client location write passes here — navigate(), a redirect hop,
|
|
96
|
+
// the browser's own back/forward — so this is the one place the
|
|
97
|
+
// navigation is declared. `read()` still holds the committed location
|
|
98
|
+
// while a navigation is pending, which is the `from` a hop wants too.
|
|
99
|
+
OBSERVE
|
|
100
|
+
? OBSERVE.attribution.withOrigin(describeNavigation(match, next, untrack(read).value), commit)
|
|
101
|
+
: commit();
|
|
57
102
|
}
|
|
58
103
|
];
|
|
59
104
|
history.init &&
|
|
@@ -100,6 +145,7 @@ export function createRouter(config) {
|
|
|
100
145
|
return compiled;
|
|
101
146
|
};
|
|
102
147
|
const renderPath = (config.history && config.history.utils && config.history.utils.renderPath) || undefined;
|
|
148
|
+
const matchPath = (pathname) => getRouteMatches(branches(), config.transformUrl ? config.transformUrl(pathname) : pathname);
|
|
103
149
|
function RouterComponent(props) {
|
|
104
150
|
// One router per app: the session (location, history, delegation, link
|
|
105
151
|
// claims, preloading) has a single owner, and a second instance would
|
|
@@ -119,7 +165,7 @@ export function createRouter(config) {
|
|
|
119
165
|
}
|
|
120
166
|
const integration = isServer
|
|
121
167
|
? staticIntegration(props.url, config.history && config.history.utils)
|
|
122
|
-
: createIntegration(history || browserHistory());
|
|
168
|
+
: createIntegration(history || browserHistory(), matchPath);
|
|
123
169
|
let context;
|
|
124
170
|
const routerState = createRouterContext(integration, branches, () => context, {
|
|
125
171
|
base: basePath,
|
|
@@ -149,9 +195,7 @@ export function createRouter(config) {
|
|
|
149
195
|
routes: config.routes,
|
|
150
196
|
config,
|
|
151
197
|
match(url) {
|
|
152
|
-
|
|
153
|
-
const pathname = config.transformUrl ? config.transformUrl(u.pathname) : u.pathname;
|
|
154
|
-
return getRouteMatches(branches(), pathname).map(({ route, path, params }) => ({
|
|
198
|
+
return matchPath(new URL(url, mockBase).pathname).map(({ route, path, params }) => ({
|
|
155
199
|
path: route.originalPath,
|
|
156
200
|
pattern: route.pattern,
|
|
157
201
|
match: path,
|
package/dist/routing.js
CHANGED
|
@@ -421,7 +421,8 @@ export function createBranches(routeDef, base = "", stack = [], branches = []) {
|
|
|
421
421
|
for (let i = 0, len = routeDefs.length; i < len; i++) {
|
|
422
422
|
const def = routeDefs[i];
|
|
423
423
|
if (def && typeof def === "object") {
|
|
424
|
-
|
|
424
|
+
// absent and explicitly `undefined` paths are the same pathless route
|
|
425
|
+
if (def.path === undefined)
|
|
425
426
|
def.path = "";
|
|
426
427
|
const routes = createRoutes(def, base);
|
|
427
428
|
for (const route of routes) {
|
|
@@ -646,7 +647,7 @@ export function createRouterContext(integration, branches, getContext, options =
|
|
|
646
647
|
read = runWithOwner(routerOwner, () => createMemo(() => {
|
|
647
648
|
const result = resolveLazySubtree(record);
|
|
648
649
|
return result instanceof Promise ? result.then(() => undefined) : undefined;
|
|
649
|
-
}));
|
|
650
|
+
}, { name: "lazyRoutes" }));
|
|
650
651
|
lazyReaders.set(record, read);
|
|
651
652
|
}
|
|
652
653
|
return read();
|
|
@@ -681,7 +682,7 @@ export function createRouterContext(integration, branches, getContext, options =
|
|
|
681
682
|
}
|
|
682
683
|
}
|
|
683
684
|
return m;
|
|
684
|
-
});
|
|
685
|
+
}, { name: "matches" });
|
|
685
686
|
const routingPending = createMemo(() => isPending(() => {
|
|
686
687
|
try {
|
|
687
688
|
matches();
|
|
@@ -692,7 +693,7 @@ export function createRouterContext(integration, branches, getContext, options =
|
|
|
692
693
|
}
|
|
693
694
|
location.search;
|
|
694
695
|
location.hash;
|
|
695
|
-
}));
|
|
696
|
+
}), { name: "routingPending" });
|
|
696
697
|
const isRouting = () => routingPending() || isPending(source);
|
|
697
698
|
const transitionIntent = () => {
|
|
698
699
|
if (!isPending(source))
|
package/dist/types.d.ts
CHANGED
|
@@ -162,14 +162,14 @@ export type LazyRouteChildren = () => readonly RouteDefinition[] | Promise<reado
|
|
|
162
162
|
routes: readonly RouteDefinition[];
|
|
163
163
|
}>;
|
|
164
164
|
export type RouteDefinition<S extends string | string[] = any, T = any> = {
|
|
165
|
-
path?: S;
|
|
166
|
-
matchFilters?: MatchFilters<S
|
|
167
|
-
preload?: RoutePreloadFunc<T
|
|
168
|
-
children?: RouteDefinition | readonly RouteDefinition[] | LazyRouteChildren;
|
|
169
|
-
component?: RouteSectionComponent<T
|
|
165
|
+
path?: S | undefined;
|
|
166
|
+
matchFilters?: MatchFilters<S> | undefined;
|
|
167
|
+
preload?: RoutePreloadFunc<T> | undefined;
|
|
168
|
+
children?: RouteDefinition | readonly RouteDefinition[] | LazyRouteChildren | undefined;
|
|
169
|
+
component?: RouteSectionComponent<T> | undefined;
|
|
170
170
|
/** Standard Schema validator for this route's search params; its input type flows into the typed path proxy. */
|
|
171
|
-
search?: StandardSchemaV1<any, any
|
|
172
|
-
info?: RouteInfo;
|
|
171
|
+
search?: StandardSchemaV1<any, any> | undefined;
|
|
172
|
+
info?: RouteInfo | undefined;
|
|
173
173
|
};
|
|
174
174
|
import type { RouteInfo } from "./index.jsx";
|
|
175
175
|
export type { RouteInfo };
|
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.24",
|
|
10
10
|
"homepage": "https://github.com/solidjs/solid-router#readme",
|
|
11
11
|
"repository": {
|
|
12
12
|
"type": "git",
|
|
@@ -38,21 +38,21 @@
|
|
|
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.8",
|
|
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.8",
|
|
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.
|
|
55
|
-
"solid-js": "^2.0.0-rc.
|
|
54
|
+
"@solidjs/web": "^2.0.0-rc.8",
|
|
55
|
+
"solid-js": "^2.0.0-rc.8"
|
|
56
56
|
},
|
|
57
57
|
"scripts": {
|
|
58
58
|
"build": "rm -rf dist && tsc && rollup -c",
|