@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.jsx
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
export * from "./components";
|
|
2
2
|
export * from "./integration";
|
|
3
|
-
export
|
|
3
|
+
export * from "./lifecycle";
|
|
4
|
+
export { useRouteData, useHref, useIsRouting, useLocation, useMatch, useNavigate, useParams, useResolvedPath, useSearchParams, useBeforeLeave, } from "./routing";
|
|
4
5
|
export { mergeSearchString as _mergeSearchString } from "./utils";
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
export function createBeforeLeave() {
|
|
2
|
+
let listeners = new Set();
|
|
3
|
+
function subscribe(listener) {
|
|
4
|
+
listeners.add(listener);
|
|
5
|
+
return () => listeners.delete(listener);
|
|
6
|
+
}
|
|
7
|
+
let ignore = false;
|
|
8
|
+
function confirm(to, options) {
|
|
9
|
+
if (ignore)
|
|
10
|
+
return !(ignore = false);
|
|
11
|
+
const e = {
|
|
12
|
+
to,
|
|
13
|
+
options,
|
|
14
|
+
defaultPrevented: false,
|
|
15
|
+
preventDefault: () => (e.defaultPrevented = true)
|
|
16
|
+
};
|
|
17
|
+
for (const l of listeners)
|
|
18
|
+
l.listener({
|
|
19
|
+
...e,
|
|
20
|
+
from: l.location,
|
|
21
|
+
retry: (force) => {
|
|
22
|
+
force && (ignore = true);
|
|
23
|
+
l.navigate(to, options);
|
|
24
|
+
}
|
|
25
|
+
});
|
|
26
|
+
return !e.defaultPrevented;
|
|
27
|
+
}
|
|
28
|
+
return {
|
|
29
|
+
subscribe,
|
|
30
|
+
confirm
|
|
31
|
+
};
|
|
32
|
+
}
|
package/dist/routing.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { Component, Accessor } from "solid-js";
|
|
2
|
-
import type { Branch, Location, LocationChangeSignal, NavigateOptions, Navigator, Params, Route, RouteContext, RouteDataFunc, RouteDefinition, RouteMatch, RouterContext, RouterIntegration, SetParams } from "./types";
|
|
2
|
+
import type { BeforeLeaveEventArgs, Branch, Location, LocationChangeSignal, NavigateOptions, Navigator, Params, Route, RouteContext, RouteDataFunc, RouteDefinition, RouteMatch, RouterContext, RouterIntegration, SetParams } from "./types";
|
|
3
3
|
export declare const RouterContextObj: import("solid-js").Context<RouterContext | undefined>;
|
|
4
4
|
export declare const RouteContextObj: import("solid-js").Context<RouteContext | undefined>;
|
|
5
5
|
export declare const useRouter: () => RouterContext;
|
|
@@ -13,7 +13,8 @@ export declare const useMatch: (path: () => string) => Accessor<import("./types"
|
|
|
13
13
|
export declare const useParams: <T extends Params>() => T;
|
|
14
14
|
declare type MaybeReturnType<T> = T extends (...args: any) => infer R ? R : T;
|
|
15
15
|
export declare const useRouteData: <T>() => MaybeReturnType<T>;
|
|
16
|
-
export declare const useSearchParams: <T extends Params>() => [T, (params: SetParams, options?: Partial<NavigateOptions
|
|
16
|
+
export declare const useSearchParams: <T extends Params>() => [T, (params: SetParams, options?: Partial<NavigateOptions>) => void];
|
|
17
|
+
export declare const useBeforeLeave: (listener: (e: BeforeLeaveEventArgs) => void) => void;
|
|
17
18
|
export declare function createRoutes(routeDef: RouteDefinition, base?: string, fallback?: Component): Route[];
|
|
18
19
|
export declare function createBranch(routes: Route[], index?: number): Branch;
|
|
19
20
|
export declare function createBranches(routeDef: RouteDefinition | RouteDefinition[], base?: string, fallback?: Component, stack?: Route[], branches?: Branch[]): Branch[];
|
package/dist/routing.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import { createComponent, createContext, createMemo, createRenderEffect, createSignal, on, onCleanup, untrack, useContext,
|
|
1
|
+
import { createComponent, createContext, createMemo, createRenderEffect, createSignal, on, onCleanup, untrack, useContext, startTransition, resetErrorBoundaries } from "solid-js";
|
|
2
2
|
import { isServer, delegateEvents } from "solid-js/web";
|
|
3
3
|
import { normalizeIntegration } from "./integration";
|
|
4
|
+
import { createBeforeLeave } from "./lifecycle";
|
|
4
5
|
import { createMemoObject, extractSearchParams, invariant, resolvePath, createMatcher, joinPaths, scoreRoute, mergeSearchString, urlDecode, expandOptionals } from "./utils";
|
|
5
6
|
const MAX_REDIRECTS = 100;
|
|
6
7
|
export const RouterContextObj = createContext();
|
|
@@ -34,10 +35,14 @@ export const useSearchParams = () => {
|
|
|
34
35
|
const navigate = useNavigate();
|
|
35
36
|
const setSearchParams = (params, options) => {
|
|
36
37
|
const searchString = untrack(() => mergeSearchString(location.search, params));
|
|
37
|
-
navigate(searchString, { scroll: false,
|
|
38
|
+
navigate(location.pathname + searchString + location.hash, { scroll: false, resolve: false, ...options });
|
|
38
39
|
};
|
|
39
40
|
return [location.query, setSearchParams];
|
|
40
41
|
};
|
|
42
|
+
export const useBeforeLeave = (listener) => {
|
|
43
|
+
const s = useRouter().beforeLeave.subscribe({ listener, location: useLocation(), navigate: useNavigate() });
|
|
44
|
+
onCleanup(s);
|
|
45
|
+
};
|
|
41
46
|
export function createRoutes(routeDef, base = "", fallback) {
|
|
42
47
|
const { component, data, children } = routeDef;
|
|
43
48
|
const isLeaf = !children || (Array.isArray(children) && !children.length);
|
|
@@ -102,7 +107,8 @@ export function createBranches(routeDef, base = "", fallback, stack = [], branch
|
|
|
102
107
|
const routes = createRoutes(def, base, fallback);
|
|
103
108
|
for (const route of routes) {
|
|
104
109
|
stack.push(route);
|
|
105
|
-
|
|
110
|
+
const isEmptyArray = Array.isArray(def.children) && def.children.length === 0;
|
|
111
|
+
if (def.children && !isEmptyArray) {
|
|
106
112
|
createBranches(def.children, route.pattern, fallback, stack, branches);
|
|
107
113
|
}
|
|
108
114
|
else {
|
|
@@ -166,6 +172,7 @@ export function createRouterContext(integration, base = "", data, out) {
|
|
|
166
172
|
const { signal: [source, setSource], utils = {} } = normalizeIntegration(integration);
|
|
167
173
|
const parsePath = utils.parsePath || (p => p);
|
|
168
174
|
const renderPath = utils.renderPath || (p => p);
|
|
175
|
+
const beforeLeave = utils.beforeLeave || createBeforeLeave();
|
|
169
176
|
const basePath = resolvePath("", base);
|
|
170
177
|
const output = isServer && out
|
|
171
178
|
? Object.assign(out, {
|
|
@@ -179,7 +186,16 @@ export function createRouterContext(integration, base = "", data, out) {
|
|
|
179
186
|
else if (basePath && !source().value) {
|
|
180
187
|
setSource({ value: basePath, replace: true, scroll: false });
|
|
181
188
|
}
|
|
182
|
-
const [isRouting,
|
|
189
|
+
const [isRouting, setIsRouting] = createSignal(false);
|
|
190
|
+
const start = async (callback) => {
|
|
191
|
+
setIsRouting(true);
|
|
192
|
+
try {
|
|
193
|
+
await startTransition(callback);
|
|
194
|
+
}
|
|
195
|
+
finally {
|
|
196
|
+
setIsRouting(false);
|
|
197
|
+
}
|
|
198
|
+
};
|
|
183
199
|
const [reference, setReference] = createSignal(source().value);
|
|
184
200
|
const [state, setState] = createSignal(source().state);
|
|
185
201
|
const location = createLocation(reference, state);
|
|
@@ -215,7 +231,7 @@ export function createRouterContext(integration, base = "", data, out) {
|
|
|
215
231
|
// A delta of 0 means stay at the current location, so it is ignored
|
|
216
232
|
}
|
|
217
233
|
else if (utils.go) {
|
|
218
|
-
utils.go(to);
|
|
234
|
+
beforeLeave.confirm(to, options) && utils.go(to);
|
|
219
235
|
}
|
|
220
236
|
else {
|
|
221
237
|
console.warn("Router integration does not support relative routing");
|
|
@@ -243,7 +259,7 @@ export function createRouterContext(integration, base = "", data, out) {
|
|
|
243
259
|
}
|
|
244
260
|
setSource({ value: resolvedTo, replace, scroll, state: nextState });
|
|
245
261
|
}
|
|
246
|
-
else {
|
|
262
|
+
else if (beforeLeave.confirm(resolvedTo, options)) {
|
|
247
263
|
const len = referrers.push({ value: current, replace, scroll, state: state() });
|
|
248
264
|
start(() => {
|
|
249
265
|
setReference(resolvedTo);
|
|
@@ -292,9 +308,6 @@ export function createRouterContext(integration, base = "", data, out) {
|
|
|
292
308
|
});
|
|
293
309
|
});
|
|
294
310
|
if (!isServer) {
|
|
295
|
-
function isSvg(el) {
|
|
296
|
-
return el.namespaceURI === "http://www.w3.org/2000/svg";
|
|
297
|
-
}
|
|
298
311
|
function handleAnchorClick(evt) {
|
|
299
312
|
if (evt.defaultPrevented ||
|
|
300
313
|
evt.button !== 0 ||
|
|
@@ -306,22 +319,20 @@ export function createRouterContext(integration, base = "", data, out) {
|
|
|
306
319
|
const a = evt
|
|
307
320
|
.composedPath()
|
|
308
321
|
.find(el => el instanceof Node && el.nodeName.toUpperCase() === "A");
|
|
309
|
-
if (!a)
|
|
322
|
+
if (!a || !a.hasAttribute("link"))
|
|
310
323
|
return;
|
|
311
|
-
const
|
|
312
|
-
|
|
313
|
-
const target = svg ? a.target.baseVal : a.target;
|
|
314
|
-
if (target || (!href && !a.hasAttribute("state")))
|
|
324
|
+
const href = a.href;
|
|
325
|
+
if (a.target || (!href && !a.hasAttribute("state")))
|
|
315
326
|
return;
|
|
316
327
|
const rel = (a.getAttribute("rel") || "").split(/\s+/);
|
|
317
328
|
if (a.hasAttribute("download") || (rel && rel.includes("external")))
|
|
318
329
|
return;
|
|
319
|
-
const url =
|
|
330
|
+
const url = new URL(href);
|
|
320
331
|
const pathname = urlDecode(url.pathname);
|
|
321
332
|
if (url.origin !== window.location.origin ||
|
|
322
333
|
(basePath && pathname && !pathname.toLowerCase().startsWith(basePath.toLowerCase())))
|
|
323
334
|
return;
|
|
324
|
-
const to = parsePath(pathname +
|
|
335
|
+
const to = parsePath(url.pathname + url.search + url.hash);
|
|
325
336
|
const state = a.getAttribute("state");
|
|
326
337
|
evt.preventDefault();
|
|
327
338
|
navigateFromRoute(baseRoute, to, {
|
|
@@ -343,7 +354,8 @@ export function createRouterContext(integration, base = "", data, out) {
|
|
|
343
354
|
isRouting,
|
|
344
355
|
renderPath,
|
|
345
356
|
parsePath,
|
|
346
|
-
navigatorFactory
|
|
357
|
+
navigatorFactory,
|
|
358
|
+
beforeLeave
|
|
347
359
|
};
|
|
348
360
|
}
|
|
349
361
|
export function createRouteContext(router, parent, child, match) {
|
package/dist/types.d.ts
CHANGED
|
@@ -93,6 +93,7 @@ export interface RouterUtils {
|
|
|
93
93
|
renderPath(path: string): string;
|
|
94
94
|
parsePath(str: string): string;
|
|
95
95
|
go(delta: number): void;
|
|
96
|
+
beforeLeave: BeforeLeaveLifecycle;
|
|
96
97
|
}
|
|
97
98
|
export interface OutputMatch {
|
|
98
99
|
originalPath: string;
|
|
@@ -112,4 +113,22 @@ export interface RouterContext {
|
|
|
112
113
|
isRouting: () => boolean;
|
|
113
114
|
renderPath(path: string): string;
|
|
114
115
|
parsePath(str: string): string;
|
|
116
|
+
beforeLeave: BeforeLeaveLifecycle;
|
|
117
|
+
}
|
|
118
|
+
export interface BeforeLeaveEventArgs {
|
|
119
|
+
from: Location;
|
|
120
|
+
to: string | number;
|
|
121
|
+
options?: Partial<NavigateOptions>;
|
|
122
|
+
readonly defaultPrevented: boolean;
|
|
123
|
+
preventDefault(): void;
|
|
124
|
+
retry(force?: boolean): void;
|
|
125
|
+
}
|
|
126
|
+
export interface BeforeLeaveListener {
|
|
127
|
+
listener(e: BeforeLeaveEventArgs): void;
|
|
128
|
+
location: Location;
|
|
129
|
+
navigate: Navigator;
|
|
130
|
+
}
|
|
131
|
+
export interface BeforeLeaveLifecycle {
|
|
132
|
+
subscribe(listener: BeforeLeaveListener): () => void;
|
|
133
|
+
confirm(to: string | number, options?: Partial<NavigateOptions>): boolean;
|
|
115
134
|
}
|
package/dist/utils.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { Params, PathMatch, Route, SetParams } from "./types";
|
|
2
|
+
export declare function normalizePath(path: string, omitSlash?: boolean): string;
|
|
2
3
|
export declare function resolvePath(base: string, path: string, from?: string): string | undefined;
|
|
3
4
|
export declare function invariant<T>(value: T | null | undefined, message: string): T;
|
|
4
5
|
export declare function joinPaths(from: string, to: string): string;
|
package/dist/utils.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { createMemo, getOwner, runWithOwner } from "solid-js";
|
|
2
2
|
const hasSchemeRegex = /^(?:[a-z0-9]+:)?\/\//i;
|
|
3
3
|
const trimPathRegex = /^\/+|\/+$/g;
|
|
4
|
-
function
|
|
4
|
+
export function normalizePath(path, omitSlash = false) {
|
|
5
5
|
const s = path.replace(trimPathRegex, "");
|
|
6
6
|
return s ? (omitSlash || /^[?#]/.test(s) ? s : "/" + s) : "";
|
|
7
7
|
}
|
|
@@ -9,8 +9,8 @@ export function resolvePath(base, path, from) {
|
|
|
9
9
|
if (hasSchemeRegex.test(path)) {
|
|
10
10
|
return undefined;
|
|
11
11
|
}
|
|
12
|
-
const basePath =
|
|
13
|
-
const fromPath = from &&
|
|
12
|
+
const basePath = normalizePath(base);
|
|
13
|
+
const fromPath = from && normalizePath(from);
|
|
14
14
|
let result = "";
|
|
15
15
|
if (!fromPath || path.startsWith("/")) {
|
|
16
16
|
result = basePath;
|
|
@@ -21,7 +21,7 @@ export function resolvePath(base, path, from) {
|
|
|
21
21
|
else {
|
|
22
22
|
result = fromPath;
|
|
23
23
|
}
|
|
24
|
-
return (result || "/") +
|
|
24
|
+
return (result || "/") + normalizePath(path, !result);
|
|
25
25
|
}
|
|
26
26
|
export function invariant(value, message) {
|
|
27
27
|
if (value == null) {
|
|
@@ -30,7 +30,7 @@ export function invariant(value, message) {
|
|
|
30
30
|
return value;
|
|
31
31
|
}
|
|
32
32
|
export function joinPaths(from, to) {
|
|
33
|
-
return
|
|
33
|
+
return normalizePath(from).replace(/\/*(\*.*)?$/g, "") + normalizePath(to);
|
|
34
34
|
}
|
|
35
35
|
export function extractSearchParams(url) {
|
|
36
36
|
const params = {};
|
package/package.json
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
"Ryan Turnquist"
|
|
7
7
|
],
|
|
8
8
|
"license": "MIT",
|
|
9
|
-
"version": "0.
|
|
9
|
+
"version": "0.5.1",
|
|
10
10
|
"homepage": "https://github.com/solidjs/solid-router#readme",
|
|
11
11
|
"repository": {
|
|
12
12
|
"type": "git",
|
|
@@ -38,23 +38,24 @@
|
|
|
38
38
|
"pretty": "prettier --write \"{src,test}/**/*.{ts,tsx}\""
|
|
39
39
|
},
|
|
40
40
|
"devDependencies": {
|
|
41
|
-
"@babel/core": "^7.
|
|
42
|
-
"@babel/preset-typescript": "^7.
|
|
43
|
-
"@rollup/plugin-babel": "5.3.
|
|
44
|
-
"@rollup/plugin-node-resolve": "13.0
|
|
45
|
-
"@types/jest": "^
|
|
46
|
-
"@types/node": "^
|
|
47
|
-
"babel-preset-solid": "^1.
|
|
48
|
-
"jest": "^
|
|
49
|
-
"
|
|
50
|
-
"
|
|
41
|
+
"@babel/core": "^7.18.13",
|
|
42
|
+
"@babel/preset-typescript": "^7.18.6",
|
|
43
|
+
"@rollup/plugin-babel": "5.3.1",
|
|
44
|
+
"@rollup/plugin-node-resolve": "13.3.0",
|
|
45
|
+
"@types/jest": "^29.0.0",
|
|
46
|
+
"@types/node": "^18.7.14",
|
|
47
|
+
"babel-preset-solid": "^1.5.3",
|
|
48
|
+
"jest": "^29.0.1",
|
|
49
|
+
"jest-environment-jsdom": "^29.2.1",
|
|
50
|
+
"prettier": "^2.7.1",
|
|
51
|
+
"rollup": "^2.79.0",
|
|
51
52
|
"rollup-plugin-terser": "^7.0.2",
|
|
52
53
|
"solid-jest": "^0.2.0",
|
|
53
|
-
"solid-js": "^1.
|
|
54
|
-
"typescript": "^4.
|
|
54
|
+
"solid-js": "^1.5.3",
|
|
55
|
+
"typescript": "^4.8.2"
|
|
55
56
|
},
|
|
56
57
|
"peerDependencies": {
|
|
57
|
-
"solid-js": "^1.3
|
|
58
|
+
"solid-js": "^1.5.3"
|
|
58
59
|
},
|
|
59
60
|
"jest": {
|
|
60
61
|
"preset": "solid-jest/preset/browser"
|