@solidjs/router 0.10.10 → 0.11.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 +8 -8
- package/dist/components.d.ts +1 -1
- package/dist/components.jsx +7 -7
- package/dist/data/action.d.ts +1 -1
- package/dist/data/action.js +3 -3
- package/dist/data/cache.d.ts +2 -4
- package/dist/data/cache.js +34 -39
- package/dist/data/events.d.ts +1 -1
- package/dist/data/events.js +2 -2
- package/dist/data/index.d.ts +4 -4
- package/dist/data/index.js +4 -4
- package/dist/index.d.ts +7 -7
- package/dist/index.js +114 -66
- package/dist/index.jsx +6 -6
- package/dist/lifecycle.d.ts +4 -1
- package/dist/lifecycle.js +37 -0
- package/dist/routers/HashRouter.d.ts +1 -1
- package/dist/routers/HashRouter.js +11 -6
- package/dist/routers/MemoryRouter.d.ts +2 -2
- package/dist/routers/MemoryRouter.js +1 -1
- package/dist/routers/Router.d.ts +1 -1
- package/dist/routers/Router.js +23 -10
- package/dist/routers/StaticRouter.d.ts +1 -1
- package/dist/routers/StaticRouter.js +1 -1
- package/dist/routers/components.d.ts +2 -2
- package/dist/routers/components.jsx +10 -9
- package/dist/routers/createRouter.d.ts +2 -2
- package/dist/routers/createRouter.js +1 -1
- package/dist/routers/index.d.ts +11 -11
- package/dist/routers/index.js +6 -6
- package/dist/routing.d.ts +2 -2
- package/dist/routing.js +13 -11
- package/dist/types.d.ts +16 -7
- package/dist/utils.d.ts +1 -1
- package/package.json +18 -21
package/README.md
CHANGED
|
@@ -565,13 +565,13 @@ Are used to injecting the optimistic updates while actions are in flight. They e
|
|
|
565
565
|
|
|
566
566
|
```jsx
|
|
567
567
|
type Submission<T, U> = {
|
|
568
|
-
input: T;
|
|
569
|
-
result
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
clear: () =>
|
|
573
|
-
retry: () =>
|
|
574
|
-
}
|
|
568
|
+
readonly input: T;
|
|
569
|
+
readonly result?: U;
|
|
570
|
+
readonly pending: boolean;
|
|
571
|
+
readonly url: string;
|
|
572
|
+
clear: () => void;
|
|
573
|
+
retry: () => void;
|
|
574
|
+
};
|
|
575
575
|
|
|
576
576
|
const submissions = useSubmissions(action, (input) => filter(input));
|
|
577
577
|
const submission = useSubmission(action, (input) => filter(input));
|
|
@@ -721,7 +721,7 @@ This is the main Router component for the browser.
|
|
|
721
721
|
|
|
722
722
|
### `<A>`
|
|
723
723
|
|
|
724
|
-
Like the `<a>` tag but supports relative paths and active class styling (requires client side JavaScript).
|
|
724
|
+
Like the `<a>` tag but supports automatic apply of base path + relative paths and active class styling (requires client side JavaScript).
|
|
725
725
|
|
|
726
726
|
The `<A>` tag has an `active` class if its href matches the current location, and `inactive` otherwise. **Note:** By default matching includes locations that are descendents (eg. href `/users` matches locations `/users` and `/users/123`), use the boolean `end` prop to prevent matching these. This is particularly useful for links to the root route `/` which would match everything.
|
|
727
727
|
|
package/dist/components.d.ts
CHANGED
package/dist/components.jsx
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { createMemo, mergeProps, splitProps } from "solid-js";
|
|
2
|
-
import { useHref, useLocation, useNavigate, useResolvedPath } from "./routing";
|
|
3
|
-
import { normalizePath } from "./utils";
|
|
2
|
+
import { useHref, useLocation, useNavigate, useResolvedPath } from "./routing.js";
|
|
3
|
+
import { normalizePath } from "./utils.js";
|
|
4
4
|
export function A(props) {
|
|
5
5
|
props = mergeProps({ inactiveClass: "inactive", activeClass: "active" }, props);
|
|
6
6
|
const [, rest] = splitProps(props, [
|
|
@@ -17,17 +17,17 @@ export function A(props) {
|
|
|
17
17
|
const isActive = createMemo(() => {
|
|
18
18
|
const to_ = to();
|
|
19
19
|
if (to_ === undefined)
|
|
20
|
-
return false;
|
|
20
|
+
return [false, false];
|
|
21
21
|
const path = normalizePath(to_.split(/[?#]/, 1)[0]).toLowerCase();
|
|
22
22
|
const loc = normalizePath(location.pathname).toLowerCase();
|
|
23
|
-
return props.end ? path === loc : loc.startsWith(path);
|
|
23
|
+
return [props.end ? path === loc : loc.startsWith(path), path === loc];
|
|
24
24
|
});
|
|
25
25
|
return (<a {...rest} href={href() || props.href} state={JSON.stringify(props.state)} classList={{
|
|
26
26
|
...(props.class && { [props.class]: true }),
|
|
27
|
-
[props.inactiveClass]: !isActive(),
|
|
28
|
-
[props.activeClass]: isActive(),
|
|
27
|
+
[props.inactiveClass]: !isActive()[0],
|
|
28
|
+
[props.activeClass]: isActive()[0],
|
|
29
29
|
...rest.classList
|
|
30
|
-
}} link aria-current={isActive() ? "page" : undefined}/>);
|
|
30
|
+
}} link aria-current={isActive()[1] ? "page" : undefined}/>);
|
|
31
31
|
}
|
|
32
32
|
export function Navigate(props) {
|
|
33
33
|
const navigate = useNavigate();
|
package/dist/data/action.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { JSX } from "solid-js";
|
|
2
|
-
import { Submission } from "../types";
|
|
2
|
+
import { Submission } from "../types.js";
|
|
3
3
|
export type Action<T extends Array<any>, U> = (T extends [FormData] | [] ? JSX.SerializableAttributeValue : unknown) & ((...vars: T) => Promise<U>) & {
|
|
4
4
|
url: string;
|
|
5
5
|
with<A extends any[], B extends any[]>(this: (this: any, ...args: [...A, ...B]) => Promise<U>, ...args: A): Action<B, U>;
|
package/dist/data/action.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { $TRACK, createMemo, createSignal, onCleanup, getOwner } from "solid-js";
|
|
2
2
|
import { isServer } from "solid-js/web";
|
|
3
|
-
import { useRouter } from "../routing";
|
|
4
|
-
import { redirectStatusCodes, mockBase } from "../utils";
|
|
5
|
-
import { cacheKeyOp, hashKey, revalidate } from "./cache";
|
|
3
|
+
import { useRouter } from "../routing.js";
|
|
4
|
+
import { redirectStatusCodes, mockBase } from "../utils.js";
|
|
5
|
+
import { cacheKeyOp, hashKey, revalidate } from "./cache.js";
|
|
6
6
|
export const actions = /* #__PURE__ */ new Map();
|
|
7
7
|
export function useSubmissions(fn, filter) {
|
|
8
8
|
const router = useRouter();
|
package/dist/data/cache.d.ts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
import { type Signal } from "solid-js";
|
|
2
1
|
import { type ReconcileOptions } from "solid-js/store";
|
|
3
|
-
|
|
2
|
+
import { CacheEntry } from "../types.js";
|
|
4
3
|
export declare function revalidate(key?: string | string[] | void, force?: boolean): Promise<void>;
|
|
5
4
|
export declare function cacheKeyOp(key: string | string[] | void, fn: (cacheEntry: CacheEntry) => void): void;
|
|
6
5
|
export type CachedFunction<T extends (...args: any) => U | Response, U> = T & {
|
|
@@ -10,7 +9,6 @@ export type CachedFunction<T extends (...args: any) => U | Response, U> = T & {
|
|
|
10
9
|
export declare function cache<T extends (...args: any) => U | Response, U>(fn: T, name: string, options?: ReconcileOptions): CachedFunction<T, U>;
|
|
11
10
|
export declare namespace cache {
|
|
12
11
|
var set: (key: string, value: any) => void;
|
|
13
|
-
var clear: () =>
|
|
12
|
+
var clear: () => void;
|
|
14
13
|
}
|
|
15
14
|
export declare function hashKey<T extends Array<any>>(args: T): string;
|
|
16
|
-
export {};
|
package/dist/data/cache.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { createSignal, getOwner, onCleanup, sharedConfig, startTransition } from "solid-js";
|
|
1
|
+
import { createSignal, getListener, getOwner, onCleanup, sharedConfig, startTransition } from "solid-js";
|
|
2
2
|
import { createStore, reconcile } from "solid-js/store";
|
|
3
3
|
import { getRequestEvent, isServer } from "solid-js/web";
|
|
4
|
-
import { useNavigate, getIntent } from "../routing";
|
|
5
|
-
import { redirectStatusCodes } from "../utils";
|
|
4
|
+
import { useNavigate, getIntent } from "../routing.js";
|
|
5
|
+
import { redirectStatusCodes } from "../utils.js";
|
|
6
6
|
const LocationHeader = "Location";
|
|
7
7
|
const PRELOAD_TIMEOUT = 5000;
|
|
8
8
|
const CACHE_TIMEOUT = 180000;
|
|
@@ -12,7 +12,7 @@ if (!isServer) {
|
|
|
12
12
|
setInterval(() => {
|
|
13
13
|
const now = Date.now();
|
|
14
14
|
for (let [k, v] of cacheMap.entries()) {
|
|
15
|
-
if (!v[3].
|
|
15
|
+
if (!v[3].count && now - v[0] > CACHE_TIMEOUT) {
|
|
16
16
|
cacheMap.delete(k);
|
|
17
17
|
}
|
|
18
18
|
}
|
|
@@ -21,17 +21,17 @@ if (!isServer) {
|
|
|
21
21
|
function getCache() {
|
|
22
22
|
if (!isServer)
|
|
23
23
|
return cacheMap;
|
|
24
|
-
const req = getRequestEvent()
|
|
24
|
+
const req = getRequestEvent();
|
|
25
25
|
if (!req)
|
|
26
26
|
throw new Error("Cannot find cache context");
|
|
27
|
-
return req.
|
|
27
|
+
return (req.router || (req.router = {})).cache || (req.router.cache = new Map());
|
|
28
28
|
}
|
|
29
29
|
export function revalidate(key, force = true) {
|
|
30
30
|
return startTransition(() => {
|
|
31
31
|
const now = Date.now();
|
|
32
32
|
cacheKeyOp(key, entry => {
|
|
33
33
|
force && (entry[0] = 0); //force cache miss
|
|
34
|
-
|
|
34
|
+
entry[3][1](now); // retrigger live signals
|
|
35
35
|
});
|
|
36
36
|
});
|
|
37
37
|
}
|
|
@@ -42,10 +42,6 @@ export function cacheKeyOp(key, fn) {
|
|
|
42
42
|
fn(cacheMap.get(k));
|
|
43
43
|
}
|
|
44
44
|
}
|
|
45
|
-
function revalidateSignals(set, time) {
|
|
46
|
-
for (let s of set)
|
|
47
|
-
s[1](time);
|
|
48
|
-
}
|
|
49
45
|
export function cache(fn, name, options) {
|
|
50
46
|
const [store, setStore] = createStore({});
|
|
51
47
|
// prioritize GET for server functions
|
|
@@ -59,16 +55,20 @@ export function cache(fn, name, options) {
|
|
|
59
55
|
const now = Date.now();
|
|
60
56
|
const key = name + hashKey(args);
|
|
61
57
|
let cached = cache.get(key);
|
|
62
|
-
let
|
|
63
|
-
if (
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
});
|
|
67
|
-
onCleanup(() => cached[3].delete(version));
|
|
68
|
-
version[0](); // track it;
|
|
58
|
+
let tracking;
|
|
59
|
+
if (getListener() && !isServer) {
|
|
60
|
+
tracking = true;
|
|
61
|
+
onCleanup(() => cached[3].count--);
|
|
69
62
|
}
|
|
70
|
-
if (cached &&
|
|
71
|
-
|
|
63
|
+
if (cached &&
|
|
64
|
+
(isServer ||
|
|
65
|
+
intent === "native" ||
|
|
66
|
+
(cached[0] && cached[3].count) ||
|
|
67
|
+
Date.now() - cached[0] < PRELOAD_TIMEOUT)) {
|
|
68
|
+
if (tracking) {
|
|
69
|
+
cached[3].count++;
|
|
70
|
+
cached[3][0](); // track
|
|
71
|
+
}
|
|
72
72
|
if (cached[2] === "preload" && intent !== "preload") {
|
|
73
73
|
cached[0] = now;
|
|
74
74
|
}
|
|
@@ -78,9 +78,7 @@ export function cache(fn, name, options) {
|
|
|
78
78
|
"then" in cached[1]
|
|
79
79
|
? cached[1].then(handleResponse(false), handleResponse(true))
|
|
80
80
|
: handleResponse(false)(cached[1]);
|
|
81
|
-
!isServer &&
|
|
82
|
-
intent === "navigate" &&
|
|
83
|
-
startTransition(() => revalidateSignals(cached[3], cached[0])); // update version
|
|
81
|
+
!isServer && intent === "navigate" && startTransition(() => cached[3][1](cached[0])); // update version
|
|
84
82
|
}
|
|
85
83
|
return res;
|
|
86
84
|
}
|
|
@@ -96,13 +94,16 @@ export function cache(fn, name, options) {
|
|
|
96
94
|
cached[0] = now;
|
|
97
95
|
cached[1] = res;
|
|
98
96
|
cached[2] = intent;
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
97
|
+
!isServer && intent === "navigate" && startTransition(() => cached[3][1](cached[0])); // update version
|
|
98
|
+
}
|
|
99
|
+
else {
|
|
100
|
+
cache.set(key, (cached = [now, res, intent, createSignal(now)]));
|
|
101
|
+
cached[3].count = 0;
|
|
102
|
+
}
|
|
103
|
+
if (tracking) {
|
|
104
|
+
cached[3].count++;
|
|
105
|
+
cached[3][0](); // track
|
|
103
106
|
}
|
|
104
|
-
else
|
|
105
|
-
cache.set(key, (cached = [now, res, intent, new Set(version ? [version] : [])]));
|
|
106
107
|
if (intent !== "preload") {
|
|
107
108
|
res =
|
|
108
109
|
"then" in res
|
|
@@ -149,21 +150,15 @@ cache.set = (key, value) => {
|
|
|
149
150
|
const cache = getCache();
|
|
150
151
|
const now = Date.now();
|
|
151
152
|
let cached = cache.get(key);
|
|
152
|
-
let version;
|
|
153
|
-
if (getOwner()) {
|
|
154
|
-
version = createSignal(now, {
|
|
155
|
-
equals: (p, v) => v - p < 50 // margin of error
|
|
156
|
-
});
|
|
157
|
-
onCleanup(() => cached[3].delete(version));
|
|
158
|
-
}
|
|
159
153
|
if (cached) {
|
|
160
154
|
cached[0] = now;
|
|
161
155
|
cached[1] = value;
|
|
162
156
|
cached[2] = "preload";
|
|
163
|
-
version && cached[3].add(version);
|
|
164
157
|
}
|
|
165
|
-
else
|
|
166
|
-
cache.set(key, (cached = [now, value, ,
|
|
158
|
+
else {
|
|
159
|
+
cache.set(key, (cached = [now, value, , createSignal(now)]));
|
|
160
|
+
cached[3].count = 0;
|
|
161
|
+
}
|
|
167
162
|
};
|
|
168
163
|
cache.clear = () => getCache().clear();
|
|
169
164
|
function matchKey(key, keys) {
|
package/dist/data/events.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import type { RouterContext } from "../types";
|
|
1
|
+
import type { RouterContext } from "../types.js";
|
|
2
2
|
export declare function setupNativeEvents(preload?: boolean, explicitLinks?: boolean, actionBase?: string): (router: RouterContext) => void;
|
package/dist/data/events.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { delegateEvents } from "solid-js/web";
|
|
2
2
|
import { onCleanup } from "solid-js";
|
|
3
|
-
import { actions } from "./action";
|
|
4
|
-
import { mockBase } from "../utils";
|
|
3
|
+
import { actions } from "./action.js";
|
|
4
|
+
import { mockBase } from "../utils.js";
|
|
5
5
|
export function setupNativeEvents(preload = true, explicitLinks = false, actionBase = "/_server") {
|
|
6
6
|
return (router) => {
|
|
7
7
|
const basePath = router.base.path();
|
package/dist/data/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { createAsync } from "./createAsync";
|
|
2
|
-
export { action, useSubmission, useSubmissions, useAction, type Action } from "./action";
|
|
3
|
-
export { cache, revalidate, type CachedFunction } from "./cache";
|
|
4
|
-
export { redirect, reload, json } from "./response";
|
|
1
|
+
export { createAsync } from "./createAsync.js";
|
|
2
|
+
export { action, useSubmission, useSubmissions, useAction, type Action } from "./action.js";
|
|
3
|
+
export { cache, revalidate, type CachedFunction } from "./cache.js";
|
|
4
|
+
export { redirect, reload, json } from "./response.js";
|
package/dist/data/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { createAsync } from "./createAsync";
|
|
2
|
-
export { action, useSubmission, useSubmissions, useAction } from "./action";
|
|
3
|
-
export { cache, revalidate } from "./cache";
|
|
4
|
-
export { redirect, reload, json } from "./response";
|
|
1
|
+
export { createAsync } from "./createAsync.js";
|
|
2
|
+
export { action, useSubmission, useSubmissions, useAction } from "./action.js";
|
|
3
|
+
export { cache, revalidate } from "./cache.js";
|
|
4
|
+
export { redirect, reload, json } from "./response.js";
|
package/dist/index.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
export * from "./routers";
|
|
2
|
-
export * from "./components";
|
|
3
|
-
export * from "./lifecycle";
|
|
4
|
-
export { useHref, useIsRouting, useLocation, useMatch, useNavigate, useParams, useResolvedPath, useSearchParams, useBeforeLeave, } from "./routing";
|
|
5
|
-
export { mergeSearchString as _mergeSearchString } from "./utils";
|
|
6
|
-
export * from "./data";
|
|
7
|
-
export type { Location, LocationChange, NavigateOptions, Navigator, OutputMatch, Params, RouteSectionProps, RouteLoadFunc, RouteLoadFuncArgs, RouteDefinition, RouterIntegration, RouterUtils, SetParams, BeforeLeaveEventArgs } from "./types";
|
|
1
|
+
export * from "./routers/index.js";
|
|
2
|
+
export * from "./components.jsx";
|
|
3
|
+
export * from "./lifecycle.js";
|
|
4
|
+
export { useHref, useIsRouting, useLocation, useMatch, useNavigate, useParams, useResolvedPath, useSearchParams, useBeforeLeave, } from "./routing.js";
|
|
5
|
+
export { mergeSearchString as _mergeSearchString } from "./utils.js";
|
|
6
|
+
export * from "./data/index.js";
|
|
7
|
+
export type { Location, LocationChange, NavigateOptions, Navigator, OutputMatch, Params, RouteSectionProps, RouteLoadFunc, RouteLoadFuncArgs, RouteDefinition, RouterIntegration, RouterUtils, SetParams, BeforeLeaveEventArgs } from "./types.js";
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { isServer, getRequestEvent, createComponent as createComponent$1, delegateEvents, spread, mergeProps as mergeProps$1, template } from 'solid-js/web';
|
|
2
|
-
import { getOwner, runWithOwner, createMemo, createContext, onCleanup, useContext, untrack, createSignal, createRenderEffect, on, startTransition, resetErrorBoundaries, createComponent, children, mergeProps, createRoot, Show, sharedConfig, $TRACK, splitProps, createResource } from 'solid-js';
|
|
2
|
+
import { getOwner, runWithOwner, createMemo, createContext, onCleanup, useContext, untrack, createSignal, createRenderEffect, on, startTransition, resetErrorBoundaries, createComponent, children, mergeProps, createRoot, Show, getListener, sharedConfig, $TRACK, splitProps, createResource } from 'solid-js';
|
|
3
3
|
import { createStore, reconcile } from 'solid-js/store';
|
|
4
4
|
|
|
5
5
|
function createBeforeLeave() {
|
|
@@ -36,6 +36,46 @@ function createBeforeLeave() {
|
|
|
36
36
|
};
|
|
37
37
|
}
|
|
38
38
|
|
|
39
|
+
// The following supports browser initiated blocking (eg back/forward)
|
|
40
|
+
|
|
41
|
+
let depth;
|
|
42
|
+
function saveCurrentDepth() {
|
|
43
|
+
if (!window.history.state || window.history.state._depth == null) {
|
|
44
|
+
window.history.replaceState({
|
|
45
|
+
...window.history.state,
|
|
46
|
+
_depth: window.history.length - 1
|
|
47
|
+
}, "");
|
|
48
|
+
}
|
|
49
|
+
depth = window.history.state._depth;
|
|
50
|
+
}
|
|
51
|
+
if (!isServer) {
|
|
52
|
+
saveCurrentDepth();
|
|
53
|
+
}
|
|
54
|
+
function keepDepth(state) {
|
|
55
|
+
return {
|
|
56
|
+
...state,
|
|
57
|
+
_depth: window.history.state && window.history.state._depth
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
function notifyIfNotBlocked(notify, block) {
|
|
61
|
+
let ignore = false;
|
|
62
|
+
return () => {
|
|
63
|
+
const prevDepth = depth;
|
|
64
|
+
saveCurrentDepth();
|
|
65
|
+
const delta = prevDepth == null ? null : depth - prevDepth;
|
|
66
|
+
if (ignore) {
|
|
67
|
+
ignore = false;
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
if (delta && block(delta)) {
|
|
71
|
+
ignore = true;
|
|
72
|
+
window.history.go(-delta);
|
|
73
|
+
} else {
|
|
74
|
+
notify();
|
|
75
|
+
}
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
|
|
39
79
|
const hasSchemeRegex = /^(?:[a-z0-9]+:)?\/\//i;
|
|
40
80
|
const trimPathRegex = /^\/+|(\/)\/+$/g;
|
|
41
81
|
const mockBase = "http://sr";
|
|
@@ -244,21 +284,21 @@ function createRoutes(routeDef, base = "") {
|
|
|
244
284
|
component,
|
|
245
285
|
load,
|
|
246
286
|
children,
|
|
247
|
-
|
|
287
|
+
info
|
|
248
288
|
} = routeDef;
|
|
249
289
|
const isLeaf = !children || Array.isArray(children) && !children.length;
|
|
250
290
|
const shared = {
|
|
251
291
|
key: routeDef,
|
|
252
292
|
component,
|
|
253
293
|
load,
|
|
254
|
-
|
|
294
|
+
info
|
|
255
295
|
};
|
|
256
296
|
return asArray(routeDef.path).reduce((acc, path) => {
|
|
257
297
|
for (const originalPath of expandOptionals(path)) {
|
|
258
298
|
const path = joinPaths(base, originalPath);
|
|
259
299
|
let pattern = isLeaf ? path : path.split("/*", 1)[0];
|
|
260
300
|
pattern = pattern.split("/").map(s => {
|
|
261
|
-
return s.startsWith(
|
|
301
|
+
return s.startsWith(":") || s.startsWith("*") ? s : encodeURIComponent(s);
|
|
262
302
|
}).join("/");
|
|
263
303
|
acc.push({
|
|
264
304
|
...shared,
|
|
@@ -444,7 +484,7 @@ function createRouterContext(integration, getBranches, options = {}) {
|
|
|
444
484
|
untrack(() => {
|
|
445
485
|
if (typeof to === "number") {
|
|
446
486
|
if (!to) ; else if (utils.go) {
|
|
447
|
-
|
|
487
|
+
utils.go(to);
|
|
448
488
|
} else {
|
|
449
489
|
console.warn("Router integration does not support relative routing");
|
|
450
490
|
}
|
|
@@ -471,12 +511,12 @@ function createRouterContext(integration, getBranches, options = {}) {
|
|
|
471
511
|
if (resolvedTo !== current || nextState !== state()) {
|
|
472
512
|
if (isServer) {
|
|
473
513
|
const e = getRequestEvent();
|
|
474
|
-
e && (e.response =
|
|
514
|
+
e && (e.response = {
|
|
475
515
|
status: 302,
|
|
476
|
-
headers: {
|
|
516
|
+
headers: new Headers({
|
|
477
517
|
Location: resolvedTo
|
|
478
|
-
}
|
|
479
|
-
})
|
|
518
|
+
})
|
|
519
|
+
});
|
|
480
520
|
setSource({
|
|
481
521
|
value: resolvedTo,
|
|
482
522
|
replace,
|
|
@@ -554,7 +594,7 @@ function createRouterContext(integration, getBranches, options = {}) {
|
|
|
554
594
|
}
|
|
555
595
|
function initFromFlash() {
|
|
556
596
|
const e = getRequestEvent();
|
|
557
|
-
return e && e.
|
|
597
|
+
return e && e.router && e.router.submission ? [e.router.submission] : [];
|
|
558
598
|
}
|
|
559
599
|
}
|
|
560
600
|
function createRouteContext(router, parent, outlet, match, params) {
|
|
@@ -623,7 +663,7 @@ function Routes(props) {
|
|
|
623
663
|
const matches = createMemo(() => getRouteMatches(props.branches, props.routerState.location.pathname));
|
|
624
664
|
if (isServer) {
|
|
625
665
|
const e = getRequestEvent();
|
|
626
|
-
e && (e.
|
|
666
|
+
e && ((e.router || (e.router = {})).matches || (e.router.matches = matches().map(({
|
|
627
667
|
route,
|
|
628
668
|
path,
|
|
629
669
|
params
|
|
@@ -632,8 +672,8 @@ function Routes(props) {
|
|
|
632
672
|
pattern: route.pattern,
|
|
633
673
|
match: path,
|
|
634
674
|
params,
|
|
635
|
-
|
|
636
|
-
})));
|
|
675
|
+
info: route.info
|
|
676
|
+
}))));
|
|
637
677
|
}
|
|
638
678
|
const params = createMemoObject(() => {
|
|
639
679
|
const m = matches();
|
|
@@ -780,7 +820,7 @@ if (!isServer) {
|
|
|
780
820
|
setInterval(() => {
|
|
781
821
|
const now = Date.now();
|
|
782
822
|
for (let [k, v] of cacheMap.entries()) {
|
|
783
|
-
if (!v[3].
|
|
823
|
+
if (!v[3].count && now - v[0] > CACHE_TIMEOUT) {
|
|
784
824
|
cacheMap.delete(k);
|
|
785
825
|
}
|
|
786
826
|
}
|
|
@@ -788,29 +828,25 @@ if (!isServer) {
|
|
|
788
828
|
}
|
|
789
829
|
function getCache() {
|
|
790
830
|
if (!isServer) return cacheMap;
|
|
791
|
-
const req = getRequestEvent()
|
|
831
|
+
const req = getRequestEvent();
|
|
792
832
|
if (!req) throw new Error("Cannot find cache context");
|
|
793
|
-
return req.
|
|
833
|
+
return (req.router || (req.router = {})).cache || (req.router.cache = new Map());
|
|
794
834
|
}
|
|
795
835
|
function revalidate(key, force = true) {
|
|
796
836
|
return startTransition(() => {
|
|
797
837
|
const now = Date.now();
|
|
798
838
|
cacheKeyOp(key, entry => {
|
|
799
839
|
force && (entry[0] = 0); //force cache miss
|
|
800
|
-
|
|
840
|
+
entry[3][1](now); // retrigger live signals
|
|
801
841
|
});
|
|
802
842
|
});
|
|
803
843
|
}
|
|
804
|
-
|
|
805
844
|
function cacheKeyOp(key, fn) {
|
|
806
845
|
key && !Array.isArray(key) && (key = [key]);
|
|
807
846
|
for (let k of cacheMap.keys()) {
|
|
808
847
|
if (key === undefined || matchKey(k, key)) fn(cacheMap.get(k));
|
|
809
848
|
}
|
|
810
849
|
}
|
|
811
|
-
function revalidateSignals(set, time) {
|
|
812
|
-
for (let s of set) s[1](time);
|
|
813
|
-
}
|
|
814
850
|
function cache(fn, name, options) {
|
|
815
851
|
const [store, setStore] = createStore({});
|
|
816
852
|
// prioritize GET for server functions
|
|
@@ -823,27 +859,24 @@ function cache(fn, name, options) {
|
|
|
823
859
|
const now = Date.now();
|
|
824
860
|
const key = name + hashKey(args);
|
|
825
861
|
let cached = cache.get(key);
|
|
826
|
-
let
|
|
827
|
-
if (
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
});
|
|
831
|
-
|
|
832
|
-
onCleanup(() => cached[3].delete(version));
|
|
833
|
-
version[0](); // track it;
|
|
862
|
+
let tracking;
|
|
863
|
+
if (getListener() && !isServer) {
|
|
864
|
+
tracking = true;
|
|
865
|
+
onCleanup(() => cached[3].count--);
|
|
834
866
|
}
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
867
|
+
if (cached && (isServer || intent === "native" || cached[0] && cached[3].count || Date.now() - cached[0] < PRELOAD_TIMEOUT)) {
|
|
868
|
+
if (tracking) {
|
|
869
|
+
cached[3].count++;
|
|
870
|
+
cached[3][0](); // track
|
|
871
|
+
}
|
|
838
872
|
if (cached[2] === "preload" && intent !== "preload") {
|
|
839
873
|
cached[0] = now;
|
|
840
874
|
}
|
|
841
875
|
let res = cached[1];
|
|
842
876
|
if (intent !== "preload") {
|
|
843
877
|
res = "then" in cached[1] ? cached[1].then(handleResponse(false), handleResponse(true)) : handleResponse(false)(cached[1]);
|
|
844
|
-
!isServer && intent === "navigate" && startTransition(() =>
|
|
878
|
+
!isServer && intent === "navigate" && startTransition(() => cached[3][1](cached[0])); // update version
|
|
845
879
|
}
|
|
846
|
-
|
|
847
880
|
return res;
|
|
848
881
|
}
|
|
849
882
|
let res = !isServer && sharedConfig.context && sharedConfig.load ? sharedConfig.load(key) // hydrating
|
|
@@ -858,11 +891,15 @@ function cache(fn, name, options) {
|
|
|
858
891
|
cached[0] = now;
|
|
859
892
|
cached[1] = res;
|
|
860
893
|
cached[2] = intent;
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
}
|
|
894
|
+
!isServer && intent === "navigate" && startTransition(() => cached[3][1](cached[0])); // update version
|
|
895
|
+
} else {
|
|
896
|
+
cache.set(key, cached = [now, res, intent, createSignal(now)]);
|
|
897
|
+
cached[3].count = 0;
|
|
898
|
+
}
|
|
899
|
+
if (tracking) {
|
|
900
|
+
cached[3].count++;
|
|
901
|
+
cached[3][0](); // track
|
|
902
|
+
}
|
|
866
903
|
if (intent !== "preload") {
|
|
867
904
|
res = "then" in res ? res.then(handleResponse(false), handleResponse(true)) : handleResponse(false)(res);
|
|
868
905
|
}
|
|
@@ -902,20 +939,14 @@ cache.set = (key, value) => {
|
|
|
902
939
|
const cache = getCache();
|
|
903
940
|
const now = Date.now();
|
|
904
941
|
let cached = cache.get(key);
|
|
905
|
-
let version;
|
|
906
|
-
if (getOwner()) {
|
|
907
|
-
version = createSignal(now, {
|
|
908
|
-
equals: (p, v) => v - p < 50 // margin of error
|
|
909
|
-
});
|
|
910
|
-
|
|
911
|
-
onCleanup(() => cached[3].delete(version));
|
|
912
|
-
}
|
|
913
942
|
if (cached) {
|
|
914
943
|
cached[0] = now;
|
|
915
944
|
cached[1] = value;
|
|
916
945
|
cached[2] = "preload";
|
|
917
|
-
|
|
918
|
-
|
|
946
|
+
} else {
|
|
947
|
+
cache.set(key, cached = [now, value,, createSignal(now)]);
|
|
948
|
+
cached[3].count = 0;
|
|
949
|
+
}
|
|
919
950
|
};
|
|
920
951
|
cache.clear = () => getCache().clear();
|
|
921
952
|
function matchKey(key, keys) {
|
|
@@ -1148,11 +1179,13 @@ function setupNativeEvents(preload = true, explicitLinks = false, actionBase = "
|
|
|
1148
1179
|
|
|
1149
1180
|
function Router(props) {
|
|
1150
1181
|
if (isServer) return StaticRouter(props);
|
|
1182
|
+
const getSource = () => ({
|
|
1183
|
+
value: window.location.pathname + window.location.search + window.location.hash,
|
|
1184
|
+
state: window.history.state
|
|
1185
|
+
});
|
|
1186
|
+
const beforeLeave = createBeforeLeave();
|
|
1151
1187
|
return createRouter({
|
|
1152
|
-
get:
|
|
1153
|
-
value: window.location.pathname + window.location.search + window.location.hash,
|
|
1154
|
-
state: history.state
|
|
1155
|
-
}),
|
|
1188
|
+
get: getSource,
|
|
1156
1189
|
set({
|
|
1157
1190
|
value,
|
|
1158
1191
|
replace,
|
|
@@ -1160,16 +1193,27 @@ function Router(props) {
|
|
|
1160
1193
|
state
|
|
1161
1194
|
}) {
|
|
1162
1195
|
if (replace) {
|
|
1163
|
-
window.history.replaceState(state, "", value);
|
|
1196
|
+
window.history.replaceState(keepDepth(state), "", value);
|
|
1164
1197
|
} else {
|
|
1165
1198
|
window.history.pushState(state, "", value);
|
|
1166
1199
|
}
|
|
1167
1200
|
scrollToHash(window.location.hash.slice(1), scroll);
|
|
1201
|
+
saveCurrentDepth();
|
|
1168
1202
|
},
|
|
1169
|
-
init: notify => bindEvent(window, "popstate", (
|
|
1203
|
+
init: notify => bindEvent(window, "popstate", notifyIfNotBlocked(notify, delta => {
|
|
1204
|
+
if (delta && delta < 0) {
|
|
1205
|
+
return !beforeLeave.confirm(delta);
|
|
1206
|
+
} else {
|
|
1207
|
+
const s = getSource();
|
|
1208
|
+
return !beforeLeave.confirm(s.value, {
|
|
1209
|
+
state: s.state
|
|
1210
|
+
});
|
|
1211
|
+
}
|
|
1212
|
+
})),
|
|
1170
1213
|
create: setupNativeEvents(props.preload, props.explicitLinks, props.actionBase),
|
|
1171
1214
|
utils: {
|
|
1172
|
-
go: delta => window.history.go(delta)
|
|
1215
|
+
go: delta => window.history.go(delta),
|
|
1216
|
+
beforeLeave
|
|
1173
1217
|
}
|
|
1174
1218
|
})(props);
|
|
1175
1219
|
}
|
|
@@ -1186,8 +1230,10 @@ function hashParser(str) {
|
|
|
1186
1230
|
return to;
|
|
1187
1231
|
}
|
|
1188
1232
|
function HashRouter(props) {
|
|
1233
|
+
const getSource = () => window.location.hash.slice(1);
|
|
1234
|
+
const beforeLeave = createBeforeLeave();
|
|
1189
1235
|
return createRouter({
|
|
1190
|
-
get:
|
|
1236
|
+
get: getSource,
|
|
1191
1237
|
set({
|
|
1192
1238
|
value,
|
|
1193
1239
|
replace,
|
|
@@ -1195,20 +1241,22 @@ function HashRouter(props) {
|
|
|
1195
1241
|
state
|
|
1196
1242
|
}) {
|
|
1197
1243
|
if (replace) {
|
|
1198
|
-
window.history.replaceState(state, "", "#" + value);
|
|
1244
|
+
window.history.replaceState(keepDepth(state), "", "#" + value);
|
|
1199
1245
|
} else {
|
|
1200
1246
|
window.location.hash = value;
|
|
1201
1247
|
}
|
|
1202
1248
|
const hashIndex = value.indexOf("#");
|
|
1203
1249
|
const hash = hashIndex >= 0 ? value.slice(hashIndex + 1) : "";
|
|
1204
1250
|
scrollToHash(hash, scroll);
|
|
1251
|
+
saveCurrentDepth();
|
|
1205
1252
|
},
|
|
1206
|
-
init: notify => bindEvent(window, "hashchange", (
|
|
1253
|
+
init: notify => bindEvent(window, "hashchange", notifyIfNotBlocked(notify, delta => !beforeLeave.confirm(delta && delta < 0 ? delta : getSource()))),
|
|
1207
1254
|
create: setupNativeEvents(props.preload, props.explicitLinks, props.actionBase),
|
|
1208
1255
|
utils: {
|
|
1209
1256
|
go: delta => window.history.go(delta),
|
|
1210
1257
|
renderPath: path => `#${path}`,
|
|
1211
|
-
parsePath: hashParser
|
|
1258
|
+
parsePath: hashParser,
|
|
1259
|
+
beforeLeave
|
|
1212
1260
|
}
|
|
1213
1261
|
})(props);
|
|
1214
1262
|
}
|
|
@@ -1280,10 +1328,10 @@ function A(props) {
|
|
|
1280
1328
|
const location = useLocation();
|
|
1281
1329
|
const isActive = createMemo(() => {
|
|
1282
1330
|
const to_ = to();
|
|
1283
|
-
if (to_ === undefined) return false;
|
|
1331
|
+
if (to_ === undefined) return [false, false];
|
|
1284
1332
|
const path = normalizePath(to_.split(/[?#]/, 1)[0]).toLowerCase();
|
|
1285
1333
|
const loc = normalizePath(location.pathname).toLowerCase();
|
|
1286
|
-
return props.end ? path === loc : loc.startsWith(path);
|
|
1334
|
+
return [props.end ? path === loc : loc.startsWith(path), path === loc];
|
|
1287
1335
|
});
|
|
1288
1336
|
return (() => {
|
|
1289
1337
|
const _el$ = _tmpl$();
|
|
@@ -1299,14 +1347,14 @@ function A(props) {
|
|
|
1299
1347
|
...(props.class && {
|
|
1300
1348
|
[props.class]: true
|
|
1301
1349
|
}),
|
|
1302
|
-
[props.inactiveClass]: !isActive(),
|
|
1303
|
-
[props.activeClass]: isActive(),
|
|
1350
|
+
[props.inactiveClass]: !isActive()[0],
|
|
1351
|
+
[props.activeClass]: isActive()[0],
|
|
1304
1352
|
...rest.classList
|
|
1305
1353
|
};
|
|
1306
1354
|
},
|
|
1307
1355
|
"link": "",
|
|
1308
1356
|
get ["aria-current"]() {
|
|
1309
|
-
return isActive() ? "page" : undefined;
|
|
1357
|
+
return isActive()[1] ? "page" : undefined;
|
|
1310
1358
|
}
|
|
1311
1359
|
}), false, false);
|
|
1312
1360
|
return _el$;
|
|
@@ -1430,4 +1478,4 @@ function json(data, init) {
|
|
|
1430
1478
|
return response;
|
|
1431
1479
|
}
|
|
1432
1480
|
|
|
1433
|
-
export { A, HashRouter, MemoryRouter, Navigate, Route, Router, StaticRouter, mergeSearchString as _mergeSearchString, action, cache, createAsync, createBeforeLeave, createMemoryHistory, createRouter, json, redirect, reload, revalidate, useAction, useBeforeLeave, useHref, useIsRouting, useLocation, useMatch, useNavigate, useParams, useResolvedPath, useSearchParams, useSubmission, useSubmissions };
|
|
1481
|
+
export { A, HashRouter, MemoryRouter, Navigate, Route, Router, StaticRouter, mergeSearchString as _mergeSearchString, action, cache, createAsync, createBeforeLeave, createMemoryHistory, createRouter, json, keepDepth, notifyIfNotBlocked, redirect, reload, revalidate, saveCurrentDepth, useAction, useBeforeLeave, useHref, useIsRouting, useLocation, useMatch, useNavigate, useParams, useResolvedPath, useSearchParams, useSubmission, useSubmissions };
|
package/dist/index.jsx
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
export * from "./routers";
|
|
2
|
-
export * from "./components";
|
|
3
|
-
export * from "./lifecycle";
|
|
4
|
-
export { useHref, useIsRouting, useLocation, useMatch, useNavigate, useParams, useResolvedPath, useSearchParams, useBeforeLeave, } from "./routing";
|
|
5
|
-
export { mergeSearchString as _mergeSearchString } from "./utils";
|
|
6
|
-
export * from "./data";
|
|
1
|
+
export * from "./routers/index.js";
|
|
2
|
+
export * from "./components.jsx";
|
|
3
|
+
export * from "./lifecycle.js";
|
|
4
|
+
export { useHref, useIsRouting, useLocation, useMatch, useNavigate, useParams, useResolvedPath, useSearchParams, useBeforeLeave, } from "./routing.js";
|
|
5
|
+
export { mergeSearchString as _mergeSearchString } from "./utils.js";
|
|
6
|
+
export * from "./data/index.js";
|
package/dist/lifecycle.d.ts
CHANGED
|
@@ -1,2 +1,5 @@
|
|
|
1
|
-
import { BeforeLeaveLifecycle } from "./types";
|
|
1
|
+
import { BeforeLeaveLifecycle, LocationChange } from "./types.js";
|
|
2
2
|
export declare function createBeforeLeave(): BeforeLeaveLifecycle;
|
|
3
|
+
export declare function saveCurrentDepth(): void;
|
|
4
|
+
export declare function keepDepth(state: any): any;
|
|
5
|
+
export declare function notifyIfNotBlocked(notify: (value?: string | LocationChange) => void, block: (delta: number | null) => boolean): () => void;
|
package/dist/lifecycle.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { isServer } from "solid-js/web";
|
|
1
2
|
export function createBeforeLeave() {
|
|
2
3
|
let listeners = new Set();
|
|
3
4
|
function subscribe(listener) {
|
|
@@ -30,3 +31,39 @@ export function createBeforeLeave() {
|
|
|
30
31
|
confirm
|
|
31
32
|
};
|
|
32
33
|
}
|
|
34
|
+
// The following supports browser initiated blocking (eg back/forward)
|
|
35
|
+
let depth;
|
|
36
|
+
export function saveCurrentDepth() {
|
|
37
|
+
if (!window.history.state || window.history.state._depth == null) {
|
|
38
|
+
window.history.replaceState({ ...window.history.state, _depth: window.history.length - 1 }, "");
|
|
39
|
+
}
|
|
40
|
+
depth = window.history.state._depth;
|
|
41
|
+
}
|
|
42
|
+
if (!isServer) {
|
|
43
|
+
saveCurrentDepth();
|
|
44
|
+
}
|
|
45
|
+
export function keepDepth(state) {
|
|
46
|
+
return {
|
|
47
|
+
...state,
|
|
48
|
+
_depth: window.history.state && window.history.state._depth
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
export function notifyIfNotBlocked(notify, block) {
|
|
52
|
+
let ignore = false;
|
|
53
|
+
return () => {
|
|
54
|
+
const prevDepth = depth;
|
|
55
|
+
saveCurrentDepth();
|
|
56
|
+
const delta = prevDepth == null ? null : depth - prevDepth;
|
|
57
|
+
if (ignore) {
|
|
58
|
+
ignore = false;
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
if (delta && block(delta)) {
|
|
62
|
+
ignore = true;
|
|
63
|
+
window.history.go(-delta);
|
|
64
|
+
}
|
|
65
|
+
else {
|
|
66
|
+
notify();
|
|
67
|
+
}
|
|
68
|
+
};
|
|
69
|
+
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { JSX } from "solid-js";
|
|
2
|
-
import type { BaseRouterProps } from "./components";
|
|
2
|
+
import type { BaseRouterProps } from "./components.js";
|
|
3
3
|
export declare function hashParser(str: string): string;
|
|
4
4
|
export type HashRouterProps = BaseRouterProps & {
|
|
5
5
|
actionBase?: string;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import { setupNativeEvents } from "../data/events";
|
|
2
|
-
import { createRouter, scrollToHash, bindEvent } from "./createRouter";
|
|
1
|
+
import { setupNativeEvents } from "../data/events.js";
|
|
2
|
+
import { createRouter, scrollToHash, bindEvent } from "./createRouter.js";
|
|
3
|
+
import { createBeforeLeave, keepDepth, notifyIfNotBlocked, saveCurrentDepth } from "../lifecycle.js";
|
|
3
4
|
export function hashParser(str) {
|
|
4
5
|
const to = str.replace(/^.*?#/, "");
|
|
5
6
|
// Hash-only hrefs like `#foo` from plain anchors will come in as `/#foo` whereas a link to
|
|
@@ -12,11 +13,13 @@ export function hashParser(str) {
|
|
|
12
13
|
return to;
|
|
13
14
|
}
|
|
14
15
|
export function HashRouter(props) {
|
|
16
|
+
const getSource = () => window.location.hash.slice(1);
|
|
17
|
+
const beforeLeave = createBeforeLeave();
|
|
15
18
|
return createRouter({
|
|
16
|
-
get:
|
|
19
|
+
get: getSource,
|
|
17
20
|
set({ value, replace, scroll, state }) {
|
|
18
21
|
if (replace) {
|
|
19
|
-
window.history.replaceState(state, "", "#" + value);
|
|
22
|
+
window.history.replaceState(keepDepth(state), "", "#" + value);
|
|
20
23
|
}
|
|
21
24
|
else {
|
|
22
25
|
window.location.hash = value;
|
|
@@ -24,13 +27,15 @@ export function HashRouter(props) {
|
|
|
24
27
|
const hashIndex = value.indexOf("#");
|
|
25
28
|
const hash = hashIndex >= 0 ? value.slice(hashIndex + 1) : "";
|
|
26
29
|
scrollToHash(hash, scroll);
|
|
30
|
+
saveCurrentDepth();
|
|
27
31
|
},
|
|
28
|
-
init: notify => bindEvent(window, "hashchange", (
|
|
32
|
+
init: notify => bindEvent(window, "hashchange", notifyIfNotBlocked(notify, delta => !beforeLeave.confirm(delta && delta < 0 ? delta : getSource()))),
|
|
29
33
|
create: setupNativeEvents(props.preload, props.explicitLinks, props.actionBase),
|
|
30
34
|
utils: {
|
|
31
35
|
go: delta => window.history.go(delta),
|
|
32
36
|
renderPath: path => `#${path}`,
|
|
33
|
-
parsePath: hashParser
|
|
37
|
+
parsePath: hashParser,
|
|
38
|
+
beforeLeave
|
|
34
39
|
}
|
|
35
40
|
})(props);
|
|
36
41
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import type { LocationChange } from "../types";
|
|
2
|
-
import type { BaseRouterProps } from "./components";
|
|
1
|
+
import type { LocationChange } from "../types.js";
|
|
2
|
+
import type { BaseRouterProps } from "./components.jsx";
|
|
3
3
|
import type { JSX } from "solid-js";
|
|
4
4
|
export type MemoryHistory = {
|
|
5
5
|
get: () => string;
|
package/dist/routers/Router.d.ts
CHANGED
package/dist/routers/Router.js
CHANGED
|
@@ -1,28 +1,41 @@
|
|
|
1
1
|
import { isServer } from "solid-js/web";
|
|
2
|
-
import { createRouter, scrollToHash, bindEvent } from "./createRouter";
|
|
3
|
-
import { StaticRouter } from "./StaticRouter";
|
|
4
|
-
import { setupNativeEvents } from "../data/events";
|
|
2
|
+
import { createRouter, scrollToHash, bindEvent } from "./createRouter.js";
|
|
3
|
+
import { StaticRouter } from "./StaticRouter.js";
|
|
4
|
+
import { setupNativeEvents } from "../data/events.js";
|
|
5
|
+
import { createBeforeLeave, keepDepth, notifyIfNotBlocked, saveCurrentDepth } from "../lifecycle.js";
|
|
5
6
|
export function Router(props) {
|
|
6
7
|
if (isServer)
|
|
7
8
|
return StaticRouter(props);
|
|
9
|
+
const getSource = () => ({
|
|
10
|
+
value: window.location.pathname + window.location.search + window.location.hash,
|
|
11
|
+
state: window.history.state
|
|
12
|
+
});
|
|
13
|
+
const beforeLeave = createBeforeLeave();
|
|
8
14
|
return createRouter({
|
|
9
|
-
get:
|
|
10
|
-
value: window.location.pathname + window.location.search + window.location.hash,
|
|
11
|
-
state: history.state
|
|
12
|
-
}),
|
|
15
|
+
get: getSource,
|
|
13
16
|
set({ value, replace, scroll, state }) {
|
|
14
17
|
if (replace) {
|
|
15
|
-
window.history.replaceState(state, "", value);
|
|
18
|
+
window.history.replaceState(keepDepth(state), "", value);
|
|
16
19
|
}
|
|
17
20
|
else {
|
|
18
21
|
window.history.pushState(state, "", value);
|
|
19
22
|
}
|
|
20
23
|
scrollToHash(window.location.hash.slice(1), scroll);
|
|
24
|
+
saveCurrentDepth();
|
|
21
25
|
},
|
|
22
|
-
init: notify => bindEvent(window, "popstate", (
|
|
26
|
+
init: notify => bindEvent(window, "popstate", notifyIfNotBlocked(notify, delta => {
|
|
27
|
+
if (delta && delta < 0) {
|
|
28
|
+
return !beforeLeave.confirm(delta);
|
|
29
|
+
}
|
|
30
|
+
else {
|
|
31
|
+
const s = getSource();
|
|
32
|
+
return !beforeLeave.confirm(s.value, { state: s.state });
|
|
33
|
+
}
|
|
34
|
+
})),
|
|
23
35
|
create: setupNativeEvents(props.preload, props.explicitLinks, props.actionBase),
|
|
24
36
|
utils: {
|
|
25
|
-
go: delta => window.history.go(delta)
|
|
37
|
+
go: delta => window.history.go(delta),
|
|
38
|
+
beforeLeave
|
|
26
39
|
}
|
|
27
40
|
})(props);
|
|
28
41
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { Component, JSX } from "solid-js";
|
|
2
|
-
import type { MatchFilters, RouteLoadFunc, RouteDefinition, RouterIntegration, RouteSectionProps } from "../types";
|
|
2
|
+
import type { MatchFilters, RouteLoadFunc, RouteDefinition, RouterIntegration, RouteSectionProps } from "../types.ts";
|
|
3
3
|
export type BaseRouterProps = {
|
|
4
4
|
base?: string;
|
|
5
5
|
/**
|
|
@@ -15,6 +15,6 @@ export type RouteProps<S extends string, T = unknown> = {
|
|
|
15
15
|
load?: RouteLoadFunc<T>;
|
|
16
16
|
matchFilters?: MatchFilters<S>;
|
|
17
17
|
component?: Component<RouteSectionProps<T>>;
|
|
18
|
-
|
|
18
|
+
info?: Record<string, any>;
|
|
19
19
|
};
|
|
20
20
|
export declare const Route: <S extends string, T = unknown>(props: RouteProps<S, T>) => JSX.Element;
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
/*@refresh skip*/
|
|
2
2
|
import { getRequestEvent, isServer } from "solid-js/web";
|
|
3
3
|
import { children, createMemo, createRoot, mergeProps, on, Show } from "solid-js";
|
|
4
|
-
import { createBranches, createRouteContext, createRouterContext, getRouteMatches, RouteContextObj, RouterContextObj } from "../routing";
|
|
5
|
-
import { createMemoObject } from "../utils";
|
|
4
|
+
import { createBranches, createRouteContext, createRouterContext, getRouteMatches, RouteContextObj, RouterContextObj } from "../routing.js";
|
|
5
|
+
import { createMemoObject } from "../utils.js";
|
|
6
6
|
export const createRouterComponent = (router) => (props) => {
|
|
7
7
|
const { base } = props;
|
|
8
8
|
const routeDefs = children(() => props.children);
|
|
@@ -18,13 +18,14 @@ function Routes(props) {
|
|
|
18
18
|
if (isServer) {
|
|
19
19
|
const e = getRequestEvent();
|
|
20
20
|
e &&
|
|
21
|
-
(e.
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
21
|
+
((e.router || (e.router = {})).matches ||
|
|
22
|
+
(e.router.matches = matches().map(({ route, path, params }) => ({
|
|
23
|
+
path: route.originalPath,
|
|
24
|
+
pattern: route.pattern,
|
|
25
|
+
match: path,
|
|
26
|
+
params,
|
|
27
|
+
info: route.info
|
|
28
|
+
}))));
|
|
28
29
|
}
|
|
29
30
|
const params = createMemoObject(() => {
|
|
30
31
|
const m = matches();
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import type { LocationChange, RouterContext, RouterUtils } from "../types";
|
|
1
|
+
import type { LocationChange, RouterContext, RouterUtils } from "../types.ts";
|
|
2
2
|
export declare function createRouter(config: {
|
|
3
3
|
get: () => string | LocationChange;
|
|
4
4
|
set: (next: LocationChange) => void;
|
|
5
5
|
init?: (notify: (value?: string | LocationChange) => void) => () => void;
|
|
6
6
|
create?: (router: RouterContext) => void;
|
|
7
7
|
utils?: Partial<RouterUtils>;
|
|
8
|
-
}): (props: import("./components").BaseRouterProps) => import("solid-js").JSX.Element;
|
|
8
|
+
}): (props: import("./components.jsx").BaseRouterProps) => import("solid-js").JSX.Element;
|
|
9
9
|
export declare function bindEvent(target: EventTarget, type: string, handler: EventListener): () => void;
|
|
10
10
|
export declare function scrollToHash(hash: string, fallbackTop?: boolean): void;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { createSignal, onCleanup } from "solid-js";
|
|
2
|
-
import { createRouterComponent } from "./components";
|
|
2
|
+
import { createRouterComponent } from "./components.jsx";
|
|
3
3
|
function intercept([value, setValue], get, set) {
|
|
4
4
|
return [get ? () => get(value()) : value, set ? (v) => setValue(set(v)) : setValue];
|
|
5
5
|
}
|
package/dist/routers/index.d.ts
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
export { Route } from "./components";
|
|
2
|
-
export type { BaseRouterProps, RouteProps } from "./components";
|
|
3
|
-
export { createRouter } from "./createRouter";
|
|
4
|
-
export { Router } from "./Router";
|
|
5
|
-
export type { RouterProps } from "./Router";
|
|
6
|
-
export { HashRouter } from "./HashRouter";
|
|
7
|
-
export type { HashRouterProps } from "./HashRouter";
|
|
8
|
-
export { MemoryRouter, createMemoryHistory } from "./MemoryRouter";
|
|
9
|
-
export type { MemoryRouterProps, MemoryHistory } from "./MemoryRouter";
|
|
10
|
-
export { StaticRouter } from "./StaticRouter";
|
|
11
|
-
export type { StaticRouterProps } from "./StaticRouter";
|
|
1
|
+
export { Route } from "./components.jsx";
|
|
2
|
+
export type { BaseRouterProps, RouteProps } from "./components.jsx";
|
|
3
|
+
export { createRouter } from "./createRouter.js";
|
|
4
|
+
export { Router } from "./Router.js";
|
|
5
|
+
export type { RouterProps } from "./Router.js";
|
|
6
|
+
export { HashRouter } from "./HashRouter.js";
|
|
7
|
+
export type { HashRouterProps } from "./HashRouter.js";
|
|
8
|
+
export { MemoryRouter, createMemoryHistory } from "./MemoryRouter.js";
|
|
9
|
+
export type { MemoryRouterProps, MemoryHistory } from "./MemoryRouter.js";
|
|
10
|
+
export { StaticRouter } from "./StaticRouter.js";
|
|
11
|
+
export type { StaticRouterProps } from "./StaticRouter.js";
|
package/dist/routers/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
export { Route } from "./components";
|
|
2
|
-
export { createRouter } from "./createRouter";
|
|
3
|
-
export { Router } from "./Router";
|
|
4
|
-
export { HashRouter } from "./HashRouter";
|
|
5
|
-
export { MemoryRouter, createMemoryHistory } from "./MemoryRouter";
|
|
6
|
-
export { StaticRouter } from "./StaticRouter";
|
|
1
|
+
export { Route } from "./components.jsx";
|
|
2
|
+
export { createRouter } from "./createRouter.js";
|
|
3
|
+
export { Router } from "./Router.js";
|
|
4
|
+
export { HashRouter } from "./HashRouter.js";
|
|
5
|
+
export { MemoryRouter, createMemoryHistory } from "./MemoryRouter.js";
|
|
6
|
+
export { StaticRouter } from "./StaticRouter.js";
|
package/dist/routing.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { JSX, Accessor } from "solid-js";
|
|
2
|
-
import type { BeforeLeaveEventArgs, Branch, Intent, Location, MatchFilters, NavigateOptions, Navigator, Params, Route, RouteContext, RouteDefinition, RouteMatch, RouterContext, RouterIntegration, SetParams } from "./types";
|
|
2
|
+
import type { BeforeLeaveEventArgs, Branch, Intent, Location, MatchFilters, NavigateOptions, Navigator, Params, Route, RouteContext, RouteDefinition, RouteMatch, RouterContext, RouterIntegration, SetParams } from "./types.js";
|
|
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;
|
|
@@ -9,7 +9,7 @@ export declare const useHref: (to: () => string | undefined) => Accessor<string
|
|
|
9
9
|
export declare const useNavigate: () => Navigator;
|
|
10
10
|
export declare const useLocation: <S = unknown>() => Location<S>;
|
|
11
11
|
export declare const useIsRouting: () => () => boolean;
|
|
12
|
-
export declare const useMatch: <S extends string>(path: () => S, matchFilters?: MatchFilters<S> | undefined) => Accessor<import("./types").PathMatch | undefined>;
|
|
12
|
+
export declare const useMatch: <S extends string>(path: () => S, matchFilters?: MatchFilters<S> | undefined) => Accessor<import("./types.js").PathMatch | undefined>;
|
|
13
13
|
export declare const useParams: <T extends Params>() => T;
|
|
14
14
|
export declare const useSearchParams: <T extends Params>() => [Partial<T>, (params: SetParams, options?: Partial<NavigateOptions>) => void];
|
|
15
15
|
export declare const useBeforeLeave: (listener: (e: BeforeLeaveEventArgs) => void) => void;
|
package/dist/routing.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { createComponent, createContext, createMemo, createRenderEffect, createSignal, on, onCleanup, untrack, useContext, startTransition, resetErrorBoundaries } from "solid-js";
|
|
2
2
|
import { isServer, getRequestEvent } from "solid-js/web";
|
|
3
|
-
import { createBeforeLeave } from "./lifecycle";
|
|
4
|
-
import { mockBase, createMemoObject, extractSearchParams, invariant, resolvePath, createMatcher, joinPaths, scoreRoute, mergeSearchString, expandOptionals } from "./utils";
|
|
3
|
+
import { createBeforeLeave } from "./lifecycle.js";
|
|
4
|
+
import { mockBase, createMemoObject, extractSearchParams, invariant, resolvePath, createMatcher, joinPaths, scoreRoute, mergeSearchString, expandOptionals } from "./utils.js";
|
|
5
5
|
const MAX_REDIRECTS = 100;
|
|
6
6
|
export const RouterContextObj = createContext();
|
|
7
7
|
export const RouteContextObj = createContext();
|
|
@@ -56,21 +56,24 @@ export const useBeforeLeave = (listener) => {
|
|
|
56
56
|
onCleanup(s);
|
|
57
57
|
};
|
|
58
58
|
export function createRoutes(routeDef, base = "") {
|
|
59
|
-
const { component, load, children,
|
|
59
|
+
const { component, load, children, info } = routeDef;
|
|
60
60
|
const isLeaf = !children || (Array.isArray(children) && !children.length);
|
|
61
61
|
const shared = {
|
|
62
62
|
key: routeDef,
|
|
63
63
|
component,
|
|
64
64
|
load,
|
|
65
|
-
|
|
65
|
+
info
|
|
66
66
|
};
|
|
67
67
|
return asArray(routeDef.path).reduce((acc, path) => {
|
|
68
68
|
for (const originalPath of expandOptionals(path)) {
|
|
69
69
|
const path = joinPaths(base, originalPath);
|
|
70
70
|
let pattern = isLeaf ? path : path.split("/*", 1)[0];
|
|
71
|
-
pattern = pattern
|
|
72
|
-
|
|
73
|
-
|
|
71
|
+
pattern = pattern
|
|
72
|
+
.split("/")
|
|
73
|
+
.map((s) => {
|
|
74
|
+
return s.startsWith(":") || s.startsWith("*") ? s : encodeURIComponent(s);
|
|
75
|
+
})
|
|
76
|
+
.join("/");
|
|
74
77
|
acc.push({
|
|
75
78
|
...shared,
|
|
76
79
|
originalPath,
|
|
@@ -252,7 +255,7 @@ export function createRouterContext(integration, getBranches, options = {}) {
|
|
|
252
255
|
// A delta of 0 means stay at the current location, so it is ignored
|
|
253
256
|
}
|
|
254
257
|
else if (utils.go) {
|
|
255
|
-
|
|
258
|
+
utils.go(to);
|
|
256
259
|
}
|
|
257
260
|
else {
|
|
258
261
|
console.warn("Router integration does not support relative routing");
|
|
@@ -276,8 +279,7 @@ export function createRouterContext(integration, getBranches, options = {}) {
|
|
|
276
279
|
if (resolvedTo !== current || nextState !== state()) {
|
|
277
280
|
if (isServer) {
|
|
278
281
|
const e = getRequestEvent();
|
|
279
|
-
e &&
|
|
280
|
-
(e.response = new Response(null, { status: 302, headers: { Location: resolvedTo } }));
|
|
282
|
+
e && (e.response = { status: 302, headers: new Headers({ Location: resolvedTo }) });
|
|
281
283
|
setSource({ value: resolvedTo, replace, scroll, state: nextState });
|
|
282
284
|
}
|
|
283
285
|
else if (beforeLeave.confirm(resolvedTo, options)) {
|
|
@@ -347,7 +349,7 @@ export function createRouterContext(integration, getBranches, options = {}) {
|
|
|
347
349
|
}
|
|
348
350
|
function initFromFlash() {
|
|
349
351
|
const e = getRequestEvent();
|
|
350
|
-
return e && e.
|
|
352
|
+
return e && e.router && e.router.submission ? [e.router.submission] : [];
|
|
351
353
|
}
|
|
352
354
|
}
|
|
353
355
|
export function createRouteContext(router, parent, outlet, match, params) {
|
package/dist/types.d.ts
CHANGED
|
@@ -1,10 +1,16 @@
|
|
|
1
1
|
import type { Component, JSX, Signal } from "solid-js";
|
|
2
2
|
declare module "solid-js/web" {
|
|
3
3
|
interface RequestEvent {
|
|
4
|
-
response?:
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
4
|
+
response?: {
|
|
5
|
+
status?: number;
|
|
6
|
+
statusText?: string;
|
|
7
|
+
headers: Headers;
|
|
8
|
+
};
|
|
9
|
+
router?: {
|
|
10
|
+
matches?: OutputMatch[];
|
|
11
|
+
cache?: Map<string, CacheEntry>;
|
|
12
|
+
submission?: Submission<any, any>;
|
|
13
|
+
};
|
|
8
14
|
serverOnly?: boolean;
|
|
9
15
|
}
|
|
10
16
|
}
|
|
@@ -61,7 +67,7 @@ export type RouteDefinition<S extends string | string[] = any, T = unknown> = {
|
|
|
61
67
|
load?: RouteLoadFunc<T>;
|
|
62
68
|
children?: RouteDefinition | RouteDefinition[];
|
|
63
69
|
component?: Component<RouteSectionProps<T>>;
|
|
64
|
-
|
|
70
|
+
info?: Record<string, any>;
|
|
65
71
|
};
|
|
66
72
|
export type MatchFilter = readonly string[] | RegExp | ((s: string) => boolean);
|
|
67
73
|
export type PathParams<P extends string | readonly string[]> = P extends `${infer Head}/${infer Tail}` ? [...PathParams<Head>, ...PathParams<Tail>] : P extends `:${infer S}?` ? [S] : P extends `:${infer S}` ? [S] : P extends `*${infer S}` ? [S] : [];
|
|
@@ -80,7 +86,7 @@ export interface OutputMatch {
|
|
|
80
86
|
pattern: string;
|
|
81
87
|
match: string;
|
|
82
88
|
params: Params;
|
|
83
|
-
|
|
89
|
+
info?: Record<string, any>;
|
|
84
90
|
}
|
|
85
91
|
export interface Route {
|
|
86
92
|
key: unknown;
|
|
@@ -90,7 +96,7 @@ export interface Route {
|
|
|
90
96
|
load?: RouteLoadFunc;
|
|
91
97
|
matcher: (location: string) => PathMatch | null;
|
|
92
98
|
matchFilters?: MatchFilters;
|
|
93
|
-
|
|
99
|
+
info?: Record<string, any>;
|
|
94
100
|
}
|
|
95
101
|
export interface Branch {
|
|
96
102
|
routes: Route[];
|
|
@@ -151,3 +157,6 @@ export type Submission<T, U> = {
|
|
|
151
157
|
export interface MaybePreloadableComponent extends Component {
|
|
152
158
|
preload?: () => void;
|
|
153
159
|
}
|
|
160
|
+
export type CacheEntry = [number, any, Intent | undefined, Signal<number> & {
|
|
161
|
+
count: number;
|
|
162
|
+
}];
|
package/dist/utils.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { MatchFilters, Params, PathMatch, Route, SetParams } from "./types";
|
|
1
|
+
import type { MatchFilters, Params, PathMatch, Route, SetParams } from "./types.ts";
|
|
2
2
|
export declare const mockBase = "http://sr";
|
|
3
3
|
export declare const redirectStatusCodes: Set<number>;
|
|
4
4
|
export declare function normalizePath(path: string, omitSlash?: boolean): string;
|
package/package.json
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
"Ryan Turnquist"
|
|
7
7
|
],
|
|
8
8
|
"license": "MIT",
|
|
9
|
-
"version": "0.
|
|
9
|
+
"version": "0.11.1",
|
|
10
10
|
"homepage": "https://github.com/solidjs/solid-router#readme",
|
|
11
11
|
"repository": {
|
|
12
12
|
"type": "git",
|
|
@@ -29,34 +29,31 @@
|
|
|
29
29
|
],
|
|
30
30
|
"sideEffects": false,
|
|
31
31
|
"devDependencies": {
|
|
32
|
-
"@babel/core": "^7.
|
|
33
|
-
"@babel/preset-typescript": "^7.
|
|
34
|
-
"@
|
|
35
|
-
"@rollup/plugin-
|
|
36
|
-
"@rollup/plugin-
|
|
37
|
-
"@
|
|
38
|
-
"@types/
|
|
39
|
-
"
|
|
32
|
+
"@babel/core": "^7.23.9",
|
|
33
|
+
"@babel/preset-typescript": "^7.23.3",
|
|
34
|
+
"@changesets/cli": "^2.27.1",
|
|
35
|
+
"@rollup/plugin-babel": "6.0.4",
|
|
36
|
+
"@rollup/plugin-node-resolve": "15.2.3",
|
|
37
|
+
"@rollup/plugin-terser": "0.4.4",
|
|
38
|
+
"@types/jest": "^29.5.11",
|
|
39
|
+
"@types/node": "^20.11.14",
|
|
40
40
|
"babel-preset-solid": "^1.8.6",
|
|
41
|
-
"
|
|
42
|
-
"
|
|
43
|
-
"
|
|
44
|
-
"rollup": "^3.7.5",
|
|
45
|
-
"solid-jest": "^0.2.0",
|
|
41
|
+
"jsdom": "^24.0.0",
|
|
42
|
+
"prettier": "^2.7.0",
|
|
43
|
+
"rollup": "^4.9.6",
|
|
46
44
|
"solid-js": "^1.8.7",
|
|
47
|
-
"typescript": "^5.
|
|
45
|
+
"typescript": "^5.3.3",
|
|
46
|
+
"vite": "^5.0.12",
|
|
47
|
+
"vite-plugin-solid": "^2.9.1",
|
|
48
|
+
"vitest": "^1.2.2"
|
|
48
49
|
},
|
|
49
50
|
"peerDependencies": {
|
|
50
51
|
"solid-js": "^1.8.6"
|
|
51
52
|
},
|
|
52
|
-
"jest": {
|
|
53
|
-
"preset": "solid-jest/preset/browser"
|
|
54
|
-
},
|
|
55
53
|
"scripts": {
|
|
56
54
|
"build": "tsc && rollup -c",
|
|
57
|
-
"test": "
|
|
58
|
-
"test:watch": "
|
|
59
|
-
"test:coverage": "jest --coverage && npm run test:types",
|
|
55
|
+
"test": "vitest run && npm run test:types",
|
|
56
|
+
"test:watch": "vitest",
|
|
60
57
|
"test:types": "tsc --project tsconfig.test.json",
|
|
61
58
|
"pretty": "prettier --write \"{src,test}/**/*.{ts,tsx}\""
|
|
62
59
|
}
|