@solidjs/router 0.10.0-beta.5 → 0.10.0-beta.7
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 +3 -3
- package/dist/components.jsx +0 -2
- package/dist/data/action.d.ts +9 -6
- package/dist/data/action.js +39 -18
- package/dist/data/cache.d.ts +7 -2
- package/dist/data/cache.js +55 -12
- package/dist/data/events.js +3 -1
- package/dist/data/index.d.ts +2 -2
- package/dist/data/response.d.ts +5 -1
- package/dist/data/response.js +17 -5
- package/dist/index.js +121 -47
- package/dist/routers/HashRouter.d.ts +3 -2
- package/dist/routers/MemoryRouter.d.ts +20 -2
- package/dist/routers/MemoryRouter.js +21 -6
- package/dist/routers/Router.d.ts +4 -3
- package/dist/routers/StaticRouter.d.ts +4 -3
- package/dist/routers/components.d.ts +2 -2
- package/dist/routers/createRouter.d.ts +1 -1
- package/dist/routers/index.d.ts +6 -2
- package/dist/routers/index.js +1 -1
- package/dist/routing.js +5 -14
- package/dist/types.d.ts +2 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -382,12 +382,12 @@ const user = createAsync(() => getUser(params.id))
|
|
|
382
382
|
|
|
383
383
|
Actions are data mutations that can trigger invalidations and further routing. A list of prebuilt response builders can be found below(TODO).
|
|
384
384
|
```jsx
|
|
385
|
+
import { action, revalidate, redirect } from "@solidjs/router"
|
|
386
|
+
|
|
385
387
|
// anywhere
|
|
386
388
|
const myAction = action(async (data) => {
|
|
387
389
|
await doMutation(data);
|
|
388
|
-
|
|
389
|
-
invalidate: [getUser, data.id]
|
|
390
|
-
}) // returns a response
|
|
390
|
+
throw redirect("/", { revalidate: getUser.keyFor(data.id) }); // throw a response to do a redirect
|
|
391
391
|
});
|
|
392
392
|
|
|
393
393
|
// in component
|
package/dist/components.jsx
CHANGED
package/dist/data/action.d.ts
CHANGED
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
import { JSX } from "solid-js";
|
|
2
2
|
import { Submission } from "../types";
|
|
3
|
-
export type Action<T
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
export type Action<T extends Array<any>, U> = ((...vars: T) => Promise<U>) & JSX.SerializableAttributeValue & {
|
|
4
|
+
url: string;
|
|
5
|
+
with<A extends any[], B extends any[]>(this: (this: any, ...args: [...A, ...B]) => U, ...args: A): Action<B, U>;
|
|
6
|
+
};
|
|
7
|
+
export declare const actions: Map<string, Action<any, any>>;
|
|
8
|
+
export declare function useSubmissions<T extends Array<any>, U>(fn: Action<T, U>, filter?: (arg: T) => boolean): Submission<T, U>[] & {
|
|
6
9
|
pending: boolean;
|
|
7
10
|
};
|
|
8
|
-
export declare function useSubmission<T
|
|
9
|
-
export declare function useAction<T
|
|
10
|
-
export declare function action<T
|
|
11
|
+
export declare function useSubmission<T extends Array<any>, U>(fn: Action<T, U>, filter?: (arg: T) => boolean): Submission<T, U>;
|
|
12
|
+
export declare function useAction<T extends Array<any>, U>(action: Action<T, U>): (...args: Parameters<Action<T, U>>) => Promise<U>;
|
|
13
|
+
export declare function action<T extends Array<any>, U = void>(fn: (...args: T) => Promise<U>, name?: string): Action<T, U>;
|
package/dist/data/action.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { $TRACK, createMemo, createSignal } from "solid-js";
|
|
1
|
+
import { $TRACK, createMemo, createSignal, onCleanup, getOwner } from "solid-js";
|
|
2
2
|
import { isServer } from "solid-js/web";
|
|
3
3
|
import { useRouter } from "../routing";
|
|
4
4
|
import { redirectStatusCodes } from "../utils";
|
|
5
|
-
import { revalidate } from "./cache";
|
|
5
|
+
import { hashKey, revalidate } from "./cache";
|
|
6
6
|
export const actions = /* #__PURE__ */ new Map();
|
|
7
7
|
export function useSubmissions(fn, filter) {
|
|
8
8
|
const router = useRouter();
|
|
@@ -27,11 +27,11 @@ export function useSubmission(fn, filter) {
|
|
|
27
27
|
}
|
|
28
28
|
export function useAction(action) {
|
|
29
29
|
const router = useRouter();
|
|
30
|
-
return action.
|
|
30
|
+
return (...args) => action.apply(router, args);
|
|
31
31
|
}
|
|
32
32
|
export function action(fn, name) {
|
|
33
|
-
function mutate(variables) {
|
|
34
|
-
const p = fn(variables);
|
|
33
|
+
function mutate(...variables) {
|
|
34
|
+
const p = fn(...variables);
|
|
35
35
|
const [result, setResult] = createSignal();
|
|
36
36
|
let submission;
|
|
37
37
|
const router = this;
|
|
@@ -56,7 +56,7 @@ export function action(fn, name) {
|
|
|
56
56
|
},
|
|
57
57
|
retry() {
|
|
58
58
|
setResult(undefined);
|
|
59
|
-
const p = fn(variables);
|
|
59
|
+
const p = fn(...variables);
|
|
60
60
|
p.then(handler, handler);
|
|
61
61
|
return p;
|
|
62
62
|
}
|
|
@@ -66,29 +66,50 @@ export function action(fn, name) {
|
|
|
66
66
|
return p;
|
|
67
67
|
}
|
|
68
68
|
const url = fn.url || (name && `action:${name}`) || (!isServer ? `action:${fn.name}` : "");
|
|
69
|
-
mutate
|
|
69
|
+
return toAction(mutate, url);
|
|
70
|
+
}
|
|
71
|
+
function toAction(fn, url) {
|
|
72
|
+
fn.toString = () => {
|
|
70
73
|
if (!url)
|
|
71
74
|
throw new Error("Client Actions need explicit names if server rendered");
|
|
72
75
|
return url;
|
|
73
76
|
};
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
+
fn.with = function (...args) {
|
|
78
|
+
const newFn = function (...passedArgs) {
|
|
79
|
+
return fn.call(this, ...args, ...passedArgs);
|
|
80
|
+
};
|
|
81
|
+
const uri = new URL(url, "http://sar");
|
|
82
|
+
uri.searchParams.set("args", hashKey(args));
|
|
83
|
+
return toAction(newFn, uri.toString());
|
|
84
|
+
};
|
|
85
|
+
fn.url = url;
|
|
86
|
+
if (!isServer) {
|
|
87
|
+
actions.set(url, fn);
|
|
88
|
+
getOwner() && onCleanup(() => actions.delete(url));
|
|
89
|
+
}
|
|
90
|
+
return fn;
|
|
77
91
|
}
|
|
78
92
|
async function handleResponse(response, navigate) {
|
|
79
93
|
let data;
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
if (
|
|
83
|
-
|
|
94
|
+
let keys;
|
|
95
|
+
if (response instanceof Response) {
|
|
96
|
+
if (response.headers.has("X-Revalidate")) {
|
|
97
|
+
keys = response.headers.get("X-Revalidate").split(",");
|
|
84
98
|
}
|
|
85
|
-
|
|
86
|
-
|
|
99
|
+
if (response.customBody)
|
|
100
|
+
data = await response.customBody();
|
|
101
|
+
if (redirectStatusCodes.has(response.status)) {
|
|
102
|
+
const locationUrl = response.headers.get("Location") || "/";
|
|
103
|
+
if (locationUrl.startsWith("http")) {
|
|
104
|
+
window.location.href = locationUrl;
|
|
105
|
+
}
|
|
106
|
+
else {
|
|
107
|
+
navigate(locationUrl);
|
|
108
|
+
}
|
|
87
109
|
}
|
|
88
110
|
}
|
|
89
111
|
else
|
|
90
112
|
data = response;
|
|
91
|
-
|
|
92
|
-
await revalidate();
|
|
113
|
+
await revalidate(keys);
|
|
93
114
|
return data;
|
|
94
115
|
}
|
package/dist/data/cache.d.ts
CHANGED
|
@@ -1,3 +1,8 @@
|
|
|
1
1
|
import { type ReconcileOptions } from "solid-js/store";
|
|
2
|
-
export declare function revalidate(key?: string |
|
|
3
|
-
export
|
|
2
|
+
export declare function revalidate(key?: string | string[] | void): Promise<void>;
|
|
3
|
+
export type CachedFunction<T extends (...args: any) => U | Response, U> = T & {
|
|
4
|
+
keyFor: (...args: Parameters<T>) => string;
|
|
5
|
+
key: string;
|
|
6
|
+
};
|
|
7
|
+
export declare function cache<T extends (...args: any) => U | Response, U>(fn: T, name: string, options?: ReconcileOptions): CachedFunction<T, U>;
|
|
8
|
+
export declare function hashKey<T extends Array<any>>(args: T): string;
|
package/dist/data/cache.js
CHANGED
|
@@ -5,7 +5,19 @@ import { useNavigate, getIntent } from "../routing";
|
|
|
5
5
|
import { redirectStatusCodes } from "../utils";
|
|
6
6
|
const LocationHeader = "Location";
|
|
7
7
|
const PRELOAD_TIMEOUT = 5000;
|
|
8
|
+
const CACHE_TIMEOUT = 180000;
|
|
8
9
|
let cacheMap = new Map();
|
|
10
|
+
// cleanup forward/back cache
|
|
11
|
+
if (!isServer) {
|
|
12
|
+
setInterval(() => {
|
|
13
|
+
const now = Date.now();
|
|
14
|
+
for (let [k, v] of cacheMap.entries()) {
|
|
15
|
+
if (!v[3].size && now - v[0] > CACHE_TIMEOUT) {
|
|
16
|
+
cacheMap.delete(k);
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
}, 300000);
|
|
20
|
+
}
|
|
9
21
|
function getCache() {
|
|
10
22
|
if (!isServer)
|
|
11
23
|
return cacheMap;
|
|
@@ -13,13 +25,14 @@ function getCache() {
|
|
|
13
25
|
return req.routerCache || (req.routerCache = new Map());
|
|
14
26
|
}
|
|
15
27
|
export function revalidate(key) {
|
|
28
|
+
key && !Array.isArray(key) && (key = [key]);
|
|
16
29
|
return startTransition(() => {
|
|
17
30
|
const now = Date.now();
|
|
18
31
|
for (let k of cacheMap.keys()) {
|
|
19
|
-
if (key === undefined || k
|
|
20
|
-
const
|
|
21
|
-
|
|
22
|
-
|
|
32
|
+
if (key === undefined || matchKey(k, key)) {
|
|
33
|
+
const entry = cacheMap.get(k);
|
|
34
|
+
entry[0] = 0; //force cache miss
|
|
35
|
+
revalidateSignals(entry[3], now); // retrigger live signals
|
|
23
36
|
}
|
|
24
37
|
}
|
|
25
38
|
});
|
|
@@ -30,13 +43,13 @@ function revalidateSignals(set, time) {
|
|
|
30
43
|
}
|
|
31
44
|
export function cache(fn, name, options) {
|
|
32
45
|
const [store, setStore] = createStore({});
|
|
33
|
-
|
|
46
|
+
const cachedFn = ((...args) => {
|
|
34
47
|
const cache = getCache();
|
|
35
48
|
const intent = getIntent();
|
|
36
49
|
const owner = getOwner();
|
|
37
50
|
const navigate = owner ? useNavigate() : undefined;
|
|
38
51
|
const now = Date.now();
|
|
39
|
-
const key = name + (args
|
|
52
|
+
const key = name + hashKey(args);
|
|
40
53
|
let cached = cache.get(key);
|
|
41
54
|
let version;
|
|
42
55
|
if (owner) {
|
|
@@ -53,9 +66,10 @@ export function cache(fn, name, options) {
|
|
|
53
66
|
}
|
|
54
67
|
let res = cached[1];
|
|
55
68
|
if (!isServer && intent === "navigate") {
|
|
56
|
-
res =
|
|
57
|
-
|
|
58
|
-
|
|
69
|
+
res =
|
|
70
|
+
"then" in cached[1]
|
|
71
|
+
? cached[1].then(handleResponse(false), handleResponse(true))
|
|
72
|
+
: handleResponse(false)(cached[1]);
|
|
59
73
|
startTransition(() => revalidateSignals(cached[3], cached[0])); // update version
|
|
60
74
|
}
|
|
61
75
|
return res;
|
|
@@ -79,9 +93,10 @@ export function cache(fn, name, options) {
|
|
|
79
93
|
else
|
|
80
94
|
cache.set(key, (cached = [now, res, intent, new Set(version ? [version] : [])]));
|
|
81
95
|
if (intent !== "preload") {
|
|
82
|
-
res =
|
|
83
|
-
|
|
84
|
-
|
|
96
|
+
res =
|
|
97
|
+
"then" in res
|
|
98
|
+
? res.then(handleResponse(false), handleResponse(true))
|
|
99
|
+
: handleResponse(false)(res);
|
|
85
100
|
}
|
|
86
101
|
return res;
|
|
87
102
|
function handleResponse(error) {
|
|
@@ -111,4 +126,32 @@ export function cache(fn, name, options) {
|
|
|
111
126
|
};
|
|
112
127
|
}
|
|
113
128
|
});
|
|
129
|
+
cachedFn.keyFor = (...args) => name + hashKey(args);
|
|
130
|
+
cachedFn.key = name;
|
|
131
|
+
return cachedFn;
|
|
132
|
+
}
|
|
133
|
+
function matchKey(key, keys) {
|
|
134
|
+
for (let k of keys) {
|
|
135
|
+
if (key.startsWith(k))
|
|
136
|
+
return true;
|
|
137
|
+
}
|
|
138
|
+
return false;
|
|
139
|
+
}
|
|
140
|
+
// Modified from the amazing Tanstack Query library (MIT)
|
|
141
|
+
// https://github.com/TanStack/query/blob/main/packages/query-core/src/utils.ts#L168
|
|
142
|
+
export function hashKey(args) {
|
|
143
|
+
return JSON.stringify(args, (_, val) => isPlainObject(val)
|
|
144
|
+
? Object.keys(val)
|
|
145
|
+
.sort()
|
|
146
|
+
.reduce((result, key) => {
|
|
147
|
+
result[key] = val[key];
|
|
148
|
+
return result;
|
|
149
|
+
}, {})
|
|
150
|
+
: val);
|
|
151
|
+
}
|
|
152
|
+
function isPlainObject(obj) {
|
|
153
|
+
let proto;
|
|
154
|
+
return (obj != null &&
|
|
155
|
+
typeof obj === "object" &&
|
|
156
|
+
(!(proto = Object.getPrototypeOf(obj)) || proto === Object.prototype));
|
|
114
157
|
}
|
package/dist/data/events.js
CHANGED
|
@@ -81,7 +81,9 @@ export function setupNativeEvents(router) {
|
|
|
81
81
|
}
|
|
82
82
|
}
|
|
83
83
|
function handleFormSubmit(evt) {
|
|
84
|
-
let actionRef =
|
|
84
|
+
let actionRef = evt.submitter && evt.submitter.hasAttribute("formaction")
|
|
85
|
+
? evt.submitter.formAction
|
|
86
|
+
: evt.target.action;
|
|
85
87
|
if (!actionRef)
|
|
86
88
|
return;
|
|
87
89
|
if (!actionRef.startsWith("action:")) {
|
package/dist/data/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
export { createAsync } from "./createAsync";
|
|
2
|
-
export { action, useSubmission, useSubmissions, useAction } from "./action";
|
|
3
|
-
export { cache, revalidate } from "./cache";
|
|
2
|
+
export { action, useSubmission, useSubmissions, useAction, type Action } from "./action";
|
|
3
|
+
export { cache, revalidate, type CachedFunction } from "./cache";
|
|
4
4
|
export { redirect } from "./response";
|
package/dist/data/response.d.ts
CHANGED
|
@@ -1 +1,5 @@
|
|
|
1
|
-
export
|
|
1
|
+
export type RouterResponseInit = ResponseInit & {
|
|
2
|
+
revalidate?: string | string[];
|
|
3
|
+
};
|
|
4
|
+
export declare function redirect(url: string, init?: number | RouterResponseInit): Response;
|
|
5
|
+
export declare function reload(init: RouterResponseInit): Response;
|
package/dist/data/response.js
CHANGED
|
@@ -1,16 +1,28 @@
|
|
|
1
1
|
export function redirect(url, init = 302) {
|
|
2
|
-
let responseInit
|
|
3
|
-
|
|
4
|
-
|
|
2
|
+
let responseInit;
|
|
3
|
+
let revalidate;
|
|
4
|
+
if (typeof init === "number") {
|
|
5
|
+
responseInit = { status: init };
|
|
5
6
|
}
|
|
6
|
-
else
|
|
7
|
-
responseInit
|
|
7
|
+
else {
|
|
8
|
+
({ revalidate, ...responseInit } = init);
|
|
9
|
+
if (typeof responseInit.status === "undefined") {
|
|
10
|
+
responseInit.status = 302;
|
|
11
|
+
}
|
|
8
12
|
}
|
|
9
13
|
const headers = new Headers(responseInit.headers);
|
|
10
14
|
headers.set("Location", url);
|
|
15
|
+
revalidate && headers.set("X-Revalidate", revalidate.toString());
|
|
11
16
|
const response = new Response(null, {
|
|
12
17
|
...responseInit,
|
|
13
18
|
headers: headers
|
|
14
19
|
});
|
|
15
20
|
return response;
|
|
16
21
|
}
|
|
22
|
+
export function reload(init) {
|
|
23
|
+
const { revalidate, ...responseInit } = init;
|
|
24
|
+
return new Response(null, {
|
|
25
|
+
...responseInit,
|
|
26
|
+
...(revalidate ? { headers: new Headers(responseInit.headers).set("X-Revalidate", revalidate.toString()) } : {})
|
|
27
|
+
});
|
|
28
|
+
}
|
package/dist/index.js
CHANGED
|
@@ -389,7 +389,7 @@ function createRouterContext(integration, getBranches, options = {}) {
|
|
|
389
389
|
const [state, setState] = createSignal(source().state);
|
|
390
390
|
const location = createLocation(reference, state);
|
|
391
391
|
const referrers = [];
|
|
392
|
-
const submissions = createSignal(initFromFlash(
|
|
392
|
+
const submissions = createSignal(isServer ? initFromFlash() : []);
|
|
393
393
|
const baseRoute = {
|
|
394
394
|
pattern: basePath,
|
|
395
395
|
params: {},
|
|
@@ -544,15 +544,9 @@ function createRouterContext(integration, getBranches, options = {}) {
|
|
|
544
544
|
}
|
|
545
545
|
intent = prevIntent;
|
|
546
546
|
}
|
|
547
|
-
function initFromFlash(
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
const input = new Map(param.entries);
|
|
551
|
-
return [{
|
|
552
|
-
url: param.url,
|
|
553
|
-
result: param.error ? new Error(param.result) : param.result,
|
|
554
|
-
input: input
|
|
555
|
-
}];
|
|
547
|
+
function initFromFlash() {
|
|
548
|
+
const e = getRequestEvent();
|
|
549
|
+
return e && e.initialSubmission ? [e.initialSubmission] : [];
|
|
556
550
|
}
|
|
557
551
|
}
|
|
558
552
|
function createRouteContext(router, parent, outlet, match, params) {
|
|
@@ -586,7 +580,7 @@ function createRouteContext(router, parent, outlet, match, params) {
|
|
|
586
580
|
load && load({
|
|
587
581
|
params,
|
|
588
582
|
location,
|
|
589
|
-
intent: intent || "
|
|
583
|
+
intent: intent || "initial"
|
|
590
584
|
});
|
|
591
585
|
return route;
|
|
592
586
|
}
|
|
@@ -757,36 +751,51 @@ function StaticRouter(props) {
|
|
|
757
751
|
|
|
758
752
|
const LocationHeader = "Location";
|
|
759
753
|
const PRELOAD_TIMEOUT = 5000;
|
|
754
|
+
const CACHE_TIMEOUT = 180000;
|
|
760
755
|
let cacheMap = new Map();
|
|
756
|
+
|
|
757
|
+
// cleanup forward/back cache
|
|
758
|
+
if (!isServer) {
|
|
759
|
+
setInterval(() => {
|
|
760
|
+
const now = Date.now();
|
|
761
|
+
for (let [k, v] of cacheMap.entries()) {
|
|
762
|
+
if (!v[3].size && now - v[0] > CACHE_TIMEOUT) {
|
|
763
|
+
cacheMap.delete(k);
|
|
764
|
+
}
|
|
765
|
+
}
|
|
766
|
+
}, 300000);
|
|
767
|
+
}
|
|
761
768
|
function getCache() {
|
|
762
769
|
if (!isServer) return cacheMap;
|
|
763
770
|
const req = getRequestEvent() || sharedConfig.context;
|
|
764
771
|
return req.routerCache || (req.routerCache = new Map());
|
|
765
772
|
}
|
|
766
773
|
function revalidate(key) {
|
|
774
|
+
key && !Array.isArray(key) && (key = [key]);
|
|
767
775
|
return startTransition(() => {
|
|
768
776
|
const now = Date.now();
|
|
769
777
|
for (let k of cacheMap.keys()) {
|
|
770
|
-
if (key === undefined || k
|
|
771
|
-
const
|
|
772
|
-
|
|
773
|
-
|
|
778
|
+
if (key === undefined || matchKey(k, key)) {
|
|
779
|
+
const entry = cacheMap.get(k);
|
|
780
|
+
entry[0] = 0; //force cache miss
|
|
781
|
+
revalidateSignals(entry[3], now); // retrigger live signals
|
|
774
782
|
}
|
|
775
783
|
}
|
|
776
784
|
});
|
|
777
785
|
}
|
|
786
|
+
|
|
778
787
|
function revalidateSignals(set, time) {
|
|
779
788
|
for (let s of set) s[1](time);
|
|
780
789
|
}
|
|
781
790
|
function cache(fn, name, options) {
|
|
782
791
|
const [store, setStore] = createStore({});
|
|
783
|
-
|
|
792
|
+
const cachedFn = (...args) => {
|
|
784
793
|
const cache = getCache();
|
|
785
794
|
const intent = getIntent();
|
|
786
795
|
const owner = getOwner();
|
|
787
796
|
const navigate = owner ? useNavigate() : undefined;
|
|
788
797
|
const now = Date.now();
|
|
789
|
-
const key = name + (args
|
|
798
|
+
const key = name + hashKey(args);
|
|
790
799
|
let cached = cache.get(key);
|
|
791
800
|
let version;
|
|
792
801
|
if (owner) {
|
|
@@ -855,6 +864,28 @@ function cache(fn, name, options) {
|
|
|
855
864
|
};
|
|
856
865
|
}
|
|
857
866
|
};
|
|
867
|
+
cachedFn.keyFor = (...args) => name + hashKey(args);
|
|
868
|
+
cachedFn.key = name;
|
|
869
|
+
return cachedFn;
|
|
870
|
+
}
|
|
871
|
+
function matchKey(key, keys) {
|
|
872
|
+
for (let k of keys) {
|
|
873
|
+
if (key.startsWith(k)) return true;
|
|
874
|
+
}
|
|
875
|
+
return false;
|
|
876
|
+
}
|
|
877
|
+
|
|
878
|
+
// Modified from the amazing Tanstack Query library (MIT)
|
|
879
|
+
// https://github.com/TanStack/query/blob/main/packages/query-core/src/utils.ts#L168
|
|
880
|
+
function hashKey(args) {
|
|
881
|
+
return JSON.stringify(args, (_, val) => isPlainObject(val) ? Object.keys(val).sort().reduce((result, key) => {
|
|
882
|
+
result[key] = val[key];
|
|
883
|
+
return result;
|
|
884
|
+
}, {}) : val);
|
|
885
|
+
}
|
|
886
|
+
function isPlainObject(obj) {
|
|
887
|
+
let proto;
|
|
888
|
+
return obj != null && typeof obj === "object" && (!(proto = Object.getPrototypeOf(obj)) || proto === Object.prototype);
|
|
858
889
|
}
|
|
859
890
|
|
|
860
891
|
const actions = /* #__PURE__ */new Map();
|
|
@@ -879,11 +910,11 @@ function useSubmission(fn, filter) {
|
|
|
879
910
|
}
|
|
880
911
|
function useAction(action) {
|
|
881
912
|
const router = useRouter();
|
|
882
|
-
return action.
|
|
913
|
+
return (...args) => action.apply(router, args);
|
|
883
914
|
}
|
|
884
915
|
function action(fn, name) {
|
|
885
|
-
function mutate(variables) {
|
|
886
|
-
const p = fn(variables);
|
|
916
|
+
function mutate(...variables) {
|
|
917
|
+
const p = fn(...variables);
|
|
887
918
|
const [result, setResult] = createSignal();
|
|
888
919
|
let submission;
|
|
889
920
|
const router = this;
|
|
@@ -908,7 +939,7 @@ function action(fn, name) {
|
|
|
908
939
|
},
|
|
909
940
|
retry() {
|
|
910
941
|
setResult(undefined);
|
|
911
|
-
const p = fn(variables);
|
|
942
|
+
const p = fn(...variables);
|
|
912
943
|
p.then(handler, handler);
|
|
913
944
|
return p;
|
|
914
945
|
}
|
|
@@ -917,25 +948,46 @@ function action(fn, name) {
|
|
|
917
948
|
return p;
|
|
918
949
|
}
|
|
919
950
|
const url = fn.url || name && `action:${name}` || (!isServer ? `action:${fn.name}` : "");
|
|
920
|
-
mutate
|
|
951
|
+
return toAction(mutate, url);
|
|
952
|
+
}
|
|
953
|
+
function toAction(fn, url) {
|
|
954
|
+
fn.toString = () => {
|
|
921
955
|
if (!url) throw new Error("Client Actions need explicit names if server rendered");
|
|
922
956
|
return url;
|
|
923
957
|
};
|
|
924
|
-
|
|
925
|
-
|
|
958
|
+
fn.with = function (...args) {
|
|
959
|
+
const newFn = function (...passedArgs) {
|
|
960
|
+
return fn.call(this, ...args, ...passedArgs);
|
|
961
|
+
};
|
|
962
|
+
const uri = new URL(url, "http://sar");
|
|
963
|
+
uri.searchParams.set("args", hashKey(args));
|
|
964
|
+
return toAction(newFn, uri.toString());
|
|
965
|
+
};
|
|
966
|
+
fn.url = url;
|
|
967
|
+
if (!isServer) {
|
|
968
|
+
actions.set(url, fn);
|
|
969
|
+
getOwner() && onCleanup(() => actions.delete(url));
|
|
970
|
+
}
|
|
971
|
+
return fn;
|
|
926
972
|
}
|
|
927
973
|
async function handleResponse(response, navigate) {
|
|
928
974
|
let data;
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
if (
|
|
932
|
-
|
|
933
|
-
}
|
|
934
|
-
|
|
975
|
+
let keys;
|
|
976
|
+
if (response instanceof Response) {
|
|
977
|
+
if (response.headers.has("X-Revalidate")) {
|
|
978
|
+
keys = response.headers.get("X-Revalidate").split(",");
|
|
979
|
+
}
|
|
980
|
+
if (response.customBody) data = await response.customBody();
|
|
981
|
+
if (redirectStatusCodes.has(response.status)) {
|
|
982
|
+
const locationUrl = response.headers.get("Location") || "/";
|
|
983
|
+
if (locationUrl.startsWith("http")) {
|
|
984
|
+
window.location.href = locationUrl;
|
|
985
|
+
} else {
|
|
986
|
+
navigate(locationUrl);
|
|
987
|
+
}
|
|
935
988
|
}
|
|
936
989
|
} else data = response;
|
|
937
|
-
|
|
938
|
-
await revalidate();
|
|
990
|
+
await revalidate(keys);
|
|
939
991
|
return data;
|
|
940
992
|
}
|
|
941
993
|
|
|
@@ -1000,7 +1052,7 @@ function setupNativeEvents(router) {
|
|
|
1000
1052
|
}
|
|
1001
1053
|
}
|
|
1002
1054
|
function handleFormSubmit(evt) {
|
|
1003
|
-
let actionRef = evt.submitter && evt.submitter.
|
|
1055
|
+
let actionRef = evt.submitter && evt.submitter.hasAttribute("formaction") ? evt.submitter.formAction : evt.target.action;
|
|
1004
1056
|
if (!actionRef) return;
|
|
1005
1057
|
if (!actionRef.startsWith("action:")) {
|
|
1006
1058
|
const url = new URL(actionRef);
|
|
@@ -1100,7 +1152,7 @@ function HashRouter(props) {
|
|
|
1100
1152
|
})(props);
|
|
1101
1153
|
}
|
|
1102
1154
|
|
|
1103
|
-
function
|
|
1155
|
+
function createMemoryHistory() {
|
|
1104
1156
|
const entries = ["/"];
|
|
1105
1157
|
let index = 0;
|
|
1106
1158
|
const listeners = [];
|
|
@@ -1110,13 +1162,13 @@ function MemoryRouter(props) {
|
|
|
1110
1162
|
const value = entries[index];
|
|
1111
1163
|
listeners.forEach(listener => listener(value));
|
|
1112
1164
|
};
|
|
1113
|
-
return
|
|
1165
|
+
return {
|
|
1114
1166
|
get: () => entries[index],
|
|
1115
|
-
set({
|
|
1167
|
+
set: ({
|
|
1116
1168
|
value,
|
|
1117
1169
|
scroll,
|
|
1118
1170
|
replace
|
|
1119
|
-
}) {
|
|
1171
|
+
}) => {
|
|
1120
1172
|
if (replace) {
|
|
1121
1173
|
entries[index] = value;
|
|
1122
1174
|
} else {
|
|
@@ -1127,20 +1179,34 @@ function MemoryRouter(props) {
|
|
|
1127
1179
|
scrollToHash(value.split("#")[1] || "", true);
|
|
1128
1180
|
}
|
|
1129
1181
|
},
|
|
1130
|
-
|
|
1182
|
+
back: () => {
|
|
1183
|
+
go(-1);
|
|
1184
|
+
},
|
|
1185
|
+
forward: () => {
|
|
1186
|
+
go(1);
|
|
1187
|
+
},
|
|
1188
|
+
go,
|
|
1189
|
+
listen: listener => {
|
|
1131
1190
|
listeners.push(listener);
|
|
1132
1191
|
return () => {
|
|
1133
1192
|
const index = listeners.indexOf(listener);
|
|
1134
1193
|
listeners.splice(index, 1);
|
|
1135
1194
|
};
|
|
1136
|
-
}
|
|
1195
|
+
}
|
|
1196
|
+
};
|
|
1197
|
+
}
|
|
1198
|
+
function MemoryRouter(props) {
|
|
1199
|
+
const memoryHistory = props.history || createMemoryHistory();
|
|
1200
|
+
return createRouter({
|
|
1201
|
+
get: memoryHistory.get,
|
|
1202
|
+
set: memoryHistory.set,
|
|
1203
|
+
init: memoryHistory.listen,
|
|
1137
1204
|
utils: {
|
|
1138
|
-
go
|
|
1205
|
+
go: memoryHistory.go
|
|
1139
1206
|
}
|
|
1140
1207
|
})(props);
|
|
1141
1208
|
}
|
|
1142
1209
|
|
|
1143
|
-
/*@refresh skip*/
|
|
1144
1210
|
const _tmpl$ = /*#__PURE__*/template(`<a>`);
|
|
1145
1211
|
function A(props) {
|
|
1146
1212
|
props = mergeProps({
|
|
@@ -1255,16 +1321,24 @@ function subFetch(fn) {
|
|
|
1255
1321
|
}
|
|
1256
1322
|
|
|
1257
1323
|
function redirect(url, init = 302) {
|
|
1258
|
-
let responseInit
|
|
1259
|
-
|
|
1324
|
+
let responseInit;
|
|
1325
|
+
let revalidate;
|
|
1326
|
+
if (typeof init === "number") {
|
|
1260
1327
|
responseInit = {
|
|
1261
|
-
status:
|
|
1328
|
+
status: init
|
|
1262
1329
|
};
|
|
1263
|
-
} else
|
|
1264
|
-
|
|
1330
|
+
} else {
|
|
1331
|
+
({
|
|
1332
|
+
revalidate,
|
|
1333
|
+
...responseInit
|
|
1334
|
+
} = init);
|
|
1335
|
+
if (typeof responseInit.status === "undefined") {
|
|
1336
|
+
responseInit.status = 302;
|
|
1337
|
+
}
|
|
1265
1338
|
}
|
|
1266
1339
|
const headers = new Headers(responseInit.headers);
|
|
1267
1340
|
headers.set("Location", url);
|
|
1341
|
+
revalidate && headers.set("X-Revalidate", revalidate.toString());
|
|
1268
1342
|
const response = new Response(null, {
|
|
1269
1343
|
...responseInit,
|
|
1270
1344
|
headers: headers
|
|
@@ -1272,4 +1346,4 @@ function redirect(url, init = 302) {
|
|
|
1272
1346
|
return response;
|
|
1273
1347
|
}
|
|
1274
1348
|
|
|
1275
|
-
export { A, HashRouter, MemoryRouter, Navigate, Route, Router, StaticRouter, mergeSearchString as _mergeSearchString, action, cache, createAsync, createBeforeLeave, createRouter, redirect, revalidate, useAction, useBeforeLeave, useHref, useIsRouting, useLocation, useMatch, useNavigate, useParams, useResolvedPath, useSearchParams, useSubmission, useSubmissions };
|
|
1349
|
+
export { A, HashRouter, MemoryRouter, Navigate, Route, Router, StaticRouter, mergeSearchString as _mergeSearchString, action, cache, createAsync, createBeforeLeave, createMemoryHistory, createRouter, redirect, revalidate, useAction, useBeforeLeave, useHref, useIsRouting, useLocation, useMatch, useNavigate, useParams, useResolvedPath, useSearchParams, useSubmission, useSubmissions };
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { JSX } from "solid-js";
|
|
2
|
-
import type {
|
|
2
|
+
import type { BaseRouterProps } from "./components";
|
|
3
3
|
export declare function hashParser(str: string): string;
|
|
4
|
-
export
|
|
4
|
+
export type HashRouterProps = BaseRouterProps;
|
|
5
|
+
export declare function HashRouter(props: HashRouterProps): JSX.Element;
|
|
@@ -1,3 +1,21 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { LocationChange } from "../types";
|
|
2
|
+
import type { BaseRouterProps } from "./components";
|
|
2
3
|
import type { JSX } from "solid-js";
|
|
3
|
-
export
|
|
4
|
+
export type MemoryHistory = {
|
|
5
|
+
get: () => string;
|
|
6
|
+
set: (change: LocationChange) => void;
|
|
7
|
+
go: (delta: number) => void;
|
|
8
|
+
listen: (listener: (value: string) => void) => () => void;
|
|
9
|
+
};
|
|
10
|
+
export declare function createMemoryHistory(): {
|
|
11
|
+
get: () => string;
|
|
12
|
+
set: ({ value, scroll, replace }: LocationChange) => void;
|
|
13
|
+
back: () => void;
|
|
14
|
+
forward: () => void;
|
|
15
|
+
go: (n: number) => void;
|
|
16
|
+
listen: (listener: (value: string) => void) => () => void;
|
|
17
|
+
};
|
|
18
|
+
export type MemoryRouterProps = BaseRouterProps & {
|
|
19
|
+
history?: MemoryHistory;
|
|
20
|
+
};
|
|
21
|
+
export declare function MemoryRouter(props: MemoryRouterProps): JSX.Element;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { createRouter, scrollToHash } from "./createRouter";
|
|
2
|
-
export function
|
|
2
|
+
export function createMemoryHistory() {
|
|
3
3
|
const entries = ["/"];
|
|
4
4
|
let index = 0;
|
|
5
5
|
const listeners = [];
|
|
@@ -9,9 +9,9 @@ export function MemoryRouter(props) {
|
|
|
9
9
|
const value = entries[index];
|
|
10
10
|
listeners.forEach(listener => listener(value));
|
|
11
11
|
};
|
|
12
|
-
return
|
|
12
|
+
return {
|
|
13
13
|
get: () => entries[index],
|
|
14
|
-
set({ value, scroll, replace }) {
|
|
14
|
+
set: ({ value, scroll, replace }) => {
|
|
15
15
|
if (replace) {
|
|
16
16
|
entries[index] = value;
|
|
17
17
|
}
|
|
@@ -23,15 +23,30 @@ export function MemoryRouter(props) {
|
|
|
23
23
|
scrollToHash(value.split("#")[1] || "", true);
|
|
24
24
|
}
|
|
25
25
|
},
|
|
26
|
-
|
|
26
|
+
back: () => {
|
|
27
|
+
go(-1);
|
|
28
|
+
},
|
|
29
|
+
forward: () => {
|
|
30
|
+
go(1);
|
|
31
|
+
},
|
|
32
|
+
go,
|
|
33
|
+
listen: (listener) => {
|
|
27
34
|
listeners.push(listener);
|
|
28
35
|
return () => {
|
|
29
36
|
const index = listeners.indexOf(listener);
|
|
30
37
|
listeners.splice(index, 1);
|
|
31
38
|
};
|
|
32
|
-
}
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
export function MemoryRouter(props) {
|
|
43
|
+
const memoryHistory = props.history || createMemoryHistory();
|
|
44
|
+
return createRouter({
|
|
45
|
+
get: memoryHistory.get,
|
|
46
|
+
set: memoryHistory.set,
|
|
47
|
+
init: memoryHistory.listen,
|
|
33
48
|
utils: {
|
|
34
|
-
go
|
|
49
|
+
go: memoryHistory.go
|
|
35
50
|
}
|
|
36
51
|
})(props);
|
|
37
52
|
}
|
package/dist/routers/Router.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { BaseRouterProps } from "./components";
|
|
2
2
|
import type { JSX } from "solid-js";
|
|
3
|
-
export
|
|
3
|
+
export type RouterProps = BaseRouterProps & {
|
|
4
4
|
url?: string;
|
|
5
|
-
}
|
|
5
|
+
};
|
|
6
|
+
export declare function Router(props: RouterProps): JSX.Element;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import { type
|
|
1
|
+
import { type BaseRouterProps } from "./components";
|
|
2
2
|
import type { JSX } from "solid-js";
|
|
3
|
-
export
|
|
3
|
+
export type StaticRouterProps = BaseRouterProps & {
|
|
4
4
|
url?: string;
|
|
5
|
-
}
|
|
5
|
+
};
|
|
6
|
+
export declare function StaticRouter(props: StaticRouterProps): JSX.Element;
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import type { Component, JSX } from "solid-js";
|
|
2
2
|
import type { MatchFilters, RouteLoadFunc, RouterIntegration, RouteSectionProps } from "../types";
|
|
3
|
-
export type
|
|
3
|
+
export type BaseRouterProps = {
|
|
4
4
|
base?: string;
|
|
5
5
|
actionBase?: string;
|
|
6
6
|
root?: Component<RouteSectionProps>;
|
|
7
7
|
children?: JSX.Element;
|
|
8
8
|
};
|
|
9
|
-
export declare const createRouterComponent: (router: RouterIntegration) => (props:
|
|
9
|
+
export declare const createRouterComponent: (router: RouterIntegration) => (props: BaseRouterProps) => JSX.Element;
|
|
10
10
|
export type RouteProps<S extends string> = {
|
|
11
11
|
path?: S | S[];
|
|
12
12
|
children?: JSX.Element;
|
|
@@ -5,6 +5,6 @@ export declare function createRouter(config: {
|
|
|
5
5
|
init?: (notify: (value?: string | LocationChange) => void) => () => void;
|
|
6
6
|
create?: (router: RouterContext) => void;
|
|
7
7
|
utils?: Partial<RouterUtils>;
|
|
8
|
-
}): (props: import("./components").
|
|
8
|
+
}): (props: import("./components").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;
|
package/dist/routers/index.d.ts
CHANGED
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
export { Route } from "./components";
|
|
2
|
-
export type {
|
|
2
|
+
export type { BaseRouterProps, RouteProps } from "./components";
|
|
3
3
|
export { createRouter } from "./createRouter";
|
|
4
4
|
export { Router } from "./Router";
|
|
5
|
+
export type { RouterProps } from "./Router";
|
|
5
6
|
export { HashRouter } from "./HashRouter";
|
|
6
|
-
export {
|
|
7
|
+
export type { HashRouterProps } from "./HashRouter";
|
|
8
|
+
export { MemoryRouter, createMemoryHistory } from "./MemoryRouter";
|
|
9
|
+
export type { MemoryRouterProps, MemoryHistory } from "./MemoryRouter";
|
|
7
10
|
export { StaticRouter } from "./StaticRouter";
|
|
11
|
+
export type { StaticRouterProps } from "./StaticRouter";
|
package/dist/routers/index.js
CHANGED
|
@@ -2,5 +2,5 @@ export { Route } from "./components";
|
|
|
2
2
|
export { createRouter } from "./createRouter";
|
|
3
3
|
export { Router } from "./Router";
|
|
4
4
|
export { HashRouter } from "./HashRouter";
|
|
5
|
-
export { MemoryRouter } from "./MemoryRouter";
|
|
5
|
+
export { MemoryRouter, createMemoryHistory } from "./MemoryRouter";
|
|
6
6
|
export { StaticRouter } from "./StaticRouter";
|
package/dist/routing.js
CHANGED
|
@@ -202,7 +202,7 @@ export function createRouterContext(integration, getBranches, options = {}) {
|
|
|
202
202
|
const [state, setState] = createSignal(source().state);
|
|
203
203
|
const location = createLocation(reference, state);
|
|
204
204
|
const referrers = [];
|
|
205
|
-
const submissions = createSignal(initFromFlash(
|
|
205
|
+
const submissions = createSignal(isServer ? initFromFlash() : []);
|
|
206
206
|
const baseRoute = {
|
|
207
207
|
pattern: basePath,
|
|
208
208
|
params: {},
|
|
@@ -342,18 +342,9 @@ export function createRouterContext(integration, getBranches, options = {}) {
|
|
|
342
342
|
}
|
|
343
343
|
intent = prevIntent;
|
|
344
344
|
}
|
|
345
|
-
function initFromFlash(
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
return [];
|
|
349
|
-
const input = new Map(param.entries);
|
|
350
|
-
return [
|
|
351
|
-
{
|
|
352
|
-
url: param.url,
|
|
353
|
-
result: param.error ? new Error(param.result) : param.result,
|
|
354
|
-
input: input
|
|
355
|
-
}
|
|
356
|
-
];
|
|
345
|
+
function initFromFlash() {
|
|
346
|
+
const e = getRequestEvent();
|
|
347
|
+
return e && e.initialSubmission ? [e.initialSubmission] : [];
|
|
357
348
|
}
|
|
358
349
|
}
|
|
359
350
|
export function createRouteContext(router, parent, outlet, match, params) {
|
|
@@ -381,6 +372,6 @@ export function createRouteContext(router, parent, outlet, match, params) {
|
|
|
381
372
|
component &&
|
|
382
373
|
component.preload &&
|
|
383
374
|
component.preload();
|
|
384
|
-
load && load({ params, location, intent: intent || "
|
|
375
|
+
load && load({ params, location, intent: intent || "initial" });
|
|
385
376
|
return route;
|
|
386
377
|
}
|
package/dist/types.d.ts
CHANGED
|
@@ -3,6 +3,7 @@ declare module "solid-js/web" {
|
|
|
3
3
|
interface RequestEvent {
|
|
4
4
|
response?: Response;
|
|
5
5
|
routerCache?: Map<any, any>;
|
|
6
|
+
initialSubmission?: Submission<any, any>;
|
|
6
7
|
}
|
|
7
8
|
}
|
|
8
9
|
export type Params = Record<string, string>;
|
|
@@ -39,7 +40,7 @@ export interface RouterIntegration {
|
|
|
39
40
|
create?: (router: RouterContext) => void;
|
|
40
41
|
utils?: Partial<RouterUtils>;
|
|
41
42
|
}
|
|
42
|
-
export type Intent = "native" | "navigate" | "preload";
|
|
43
|
+
export type Intent = "initial" | "native" | "navigate" | "preload";
|
|
43
44
|
export interface RouteLoadFuncArgs {
|
|
44
45
|
params: Params;
|
|
45
46
|
location: Location;
|