@solidjs/router 0.10.0-beta.1 → 0.10.0-beta.2

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.
@@ -9,7 +9,7 @@ export const Router = (props) => {
9
9
  const { source, url, base } = props;
10
10
  const integration = source ||
11
11
  (isServer
12
- ? staticIntegration({ value: url || ((e = getRequestEvent()) && e.request.url) || "" })
12
+ ? staticIntegration({ value: url || ((e = getRequestEvent()) && getPath(e.request.url)) || "" })
13
13
  : pathIntegration());
14
14
  const routeDefs = children(() => props.children);
15
15
  const branches = createMemo(() => createBranches(props.root ? { component: props.root, children: routeDefs() } : routeDefs(), props.base || ""));
@@ -18,6 +18,10 @@ export const Router = (props) => {
18
18
  <Routes routerState={routerState} branches={branches()}/>
19
19
  </RouterContextObj.Provider>);
20
20
  };
21
+ function getPath(url) {
22
+ const u = new URL(url);
23
+ return u.pathname + u.search;
24
+ }
21
25
  function Routes(props) {
22
26
  const matches = createMemo(() => getRouteMatches(props.branches, props.routerState.location.pathname));
23
27
  const params = createMemoObject(() => {
@@ -49,6 +49,11 @@ export function action(fn, name) {
49
49
  const [result, setResult] = createSignal();
50
50
  let submission;
51
51
  const router = this;
52
+ async function handler(res) {
53
+ const data = await handleResponse(res, router.navigatorFactory());
54
+ data ? setResult({ data }) : submission.clear();
55
+ return data;
56
+ }
52
57
  router.submissions[1](s => [
53
58
  ...s,
54
59
  (submission = {
@@ -66,29 +71,15 @@ export function action(fn, name) {
66
71
  retry() {
67
72
  setResult(undefined);
68
73
  const p = fn(variables);
69
- p.then(async (data) => {
70
- const keys = handleResponse(data, router.navigatorFactory());
71
- await revalidate(keys);
72
- data ? setResult({ data }) : submission.clear();
73
- return data;
74
- }).catch(error => {
75
- setResult({ data: error });
76
- });
74
+ p.then(handler, handler);
77
75
  return p;
78
76
  }
79
77
  })
80
78
  ]);
81
- p.then(async (data) => {
82
- const keys = handleResponse(data, router.navigatorFactory());
83
- await revalidate(keys);
84
- data ? setResult({ data }) : submission.clear();
85
- return data;
86
- }).catch(error => {
87
- setResult({ data: error });
88
- });
79
+ p.then(handler, handler);
89
80
  return p;
90
81
  }
91
- const url = fn.url || `action:${name}` || !isServer ? `action:${fn.name}` : "";
82
+ const url = fn.url || (name && `action:${name}`) || (!isServer ? `action:${fn.name}` : "");
92
83
  mutate.toString = () => {
93
84
  if (!url)
94
85
  throw new Error("Client Actions need explicit names if server rendered");
@@ -98,7 +89,8 @@ export function action(fn, name) {
98
89
  registerAction(url, mutate);
99
90
  return mutate;
100
91
  }
101
- function handleResponse(response, navigate) {
92
+ async function handleResponse(response, navigate) {
93
+ let data;
102
94
  if (response instanceof Response && redirectStatusCodes.has(response.status)) {
103
95
  const locationUrl = response.headers.get("Location") || "/";
104
96
  if (locationUrl.startsWith("http")) {
@@ -108,6 +100,9 @@ function handleResponse(response, navigate) {
108
100
  navigate(locationUrl);
109
101
  }
110
102
  }
111
- // return keys
112
- return;
103
+ else
104
+ data = response;
105
+ // TODO: handle keys
106
+ await revalidate();
107
+ return data;
113
108
  }
@@ -52,7 +52,7 @@ export function cache(fn, name, options) {
52
52
  cached[0] = now;
53
53
  cached[1] =
54
54
  "then" in cached[1]
55
- ? cached[1].then(handleResponse)
55
+ ? cached[1].then(handleResponse, handleResponse)
56
56
  : handleResponse(cached[1]);
57
57
  cached[2] = intent;
58
58
  }
@@ -71,7 +71,7 @@ export function cache(fn, name, options) {
71
71
  if (intent !== "preload") {
72
72
  res =
73
73
  "then" in res
74
- ? res.then(handleResponse)
74
+ ? res.then(handleResponse, handleResponse)
75
75
  : handleResponse(res);
76
76
  }
77
77
  if (cached) {
@@ -86,25 +86,25 @@ export function cache(fn, name, options) {
86
86
  else
87
87
  cache.set(key, (cached = [now, res, intent, new Set(version ? [version] : [])]));
88
88
  return res;
89
- function handleRedirect(response) {
90
- startTransition(() => {
91
- let url = response.headers.get(LocationHeader);
92
- if (url && url.startsWith("/")) {
93
- navigate(url, {
94
- replace: true
95
- });
96
- }
97
- else if (!isServer && url) {
98
- window.location.href = url;
99
- }
100
- });
101
- }
102
89
  function handleResponse(v) {
103
90
  if (v instanceof Response && redirectStatusCodes.has(v.status)) {
104
- if (navigate)
105
- isServer ? handleRedirect(v) : setTimeout(() => handleRedirect(v), 0);
91
+ if (navigate) {
92
+ startTransition(() => {
93
+ let url = v.headers.get(LocationHeader);
94
+ if (url && url.startsWith("/")) {
95
+ navigate(url, {
96
+ replace: true
97
+ });
98
+ }
99
+ else if (!isServer && url) {
100
+ window.location.href = url;
101
+ }
102
+ });
103
+ }
106
104
  return;
107
105
  }
106
+ if (v instanceof Error)
107
+ throw v;
108
108
  if (isServer)
109
109
  return v;
110
110
  setStore(key, reconcile(v, options));
@@ -2,4 +2,13 @@
2
2
  * This is mock of the eventual Solid 2.0 primitive. It is not fully featured.
3
3
  */
4
4
  import { type Accessor } from "solid-js";
5
- export declare function createAsync<T>(fn: () => Promise<T>): Accessor<T | undefined>;
5
+ export declare function createAsync<T>(fn: () => Promise<T>, options: {
6
+ name?: string;
7
+ initialValue: T;
8
+ deferStream?: boolean;
9
+ }): Accessor<T>;
10
+ export declare function createAsync<T>(fn: () => Promise<T>, options?: {
11
+ name?: string;
12
+ initialValue?: T;
13
+ deferStream?: boolean;
14
+ }): Accessor<T | undefined>;
@@ -3,8 +3,8 @@
3
3
  */
4
4
  import { createResource, sharedConfig } from "solid-js";
5
5
  import { isServer } from "solid-js/web";
6
- export function createAsync(fn) {
7
- const [resource] = createResource(() => subFetch(fn), v => v);
6
+ export function createAsync(fn, options) {
7
+ const [resource] = createResource(() => subFetch(fn), v => v, options);
8
8
  return () => resource();
9
9
  }
10
10
  // mock promise while hydrating to prevent fetching
@@ -1,3 +1,4 @@
1
1
  export { createAsync } from "./createAsync";
2
2
  export { action, useSubmission, useSubmissions } from "./action";
3
3
  export { cache, revalidate } from "./cache";
4
+ export { redirect } from "./response";
@@ -1,3 +1,4 @@
1
1
  export { createAsync } from "./createAsync";
2
2
  export { action, useSubmission, useSubmissions } from "./action";
3
3
  export { cache, revalidate } from "./cache";
4
+ export { redirect } from "./response";
@@ -0,0 +1 @@
1
+ export declare function redirect(url: string, init?: number | ResponseInit): Response;
@@ -0,0 +1,16 @@
1
+ export function redirect(url, init = 302) {
2
+ let responseInit = init;
3
+ if (typeof responseInit === "number") {
4
+ responseInit = { status: responseInit };
5
+ }
6
+ else if (typeof responseInit.status === "undefined") {
7
+ responseInit.status = 302;
8
+ }
9
+ const headers = new Headers(responseInit.headers);
10
+ headers.set("Location", url);
11
+ const response = new Response(null, {
12
+ ...responseInit,
13
+ headers: headers
14
+ });
15
+ return response;
16
+ }
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { isServer, delegateEvents, getRequestEvent, createComponent as createComponent$1, spread, mergeProps as mergeProps$1, template } from 'solid-js/web';
2
- import { createSignal, onCleanup, getOwner, runWithOwner, createMemo, createContext, useContext, untrack, createRenderEffect, on, startTransition, createComponent, resetErrorBoundaries, children, createRoot, Show, mergeProps, splitProps, createResource, sharedConfig, $TRACK } from 'solid-js';
2
+ import { createSignal, onCleanup, getOwner, runWithOwner, createMemo, createContext, useContext, untrack, createRenderEffect, on, startTransition, resetErrorBoundaries, createComponent, children, createRoot, Show, mergeProps, splitProps, createResource, sharedConfig, $TRACK } from 'solid-js';
3
3
  import { createStore, reconcile } from 'solid-js/store';
4
4
 
5
5
  function bindEvent(target, type, handler) {
@@ -570,6 +570,16 @@ function createRouterContext(integration, getBranches, base = "") {
570
570
  return resolvePath(basePath, to);
571
571
  }
572
572
  };
573
+ const router = {
574
+ base: baseRoute,
575
+ location,
576
+ isRouting,
577
+ renderPath,
578
+ parsePath,
579
+ navigatorFactory,
580
+ beforeLeave,
581
+ submissions: createSignal(submissions)
582
+ };
573
583
  function navigateFromRoute(route, to, options) {
574
584
  // Untrack in case someone navigates in an effect - don't want to track `reference` or route paths
575
585
  untrack(() => {
@@ -602,7 +612,12 @@ function createRouterContext(integration, getBranches, base = "") {
602
612
  if (resolvedTo !== current || nextState !== state()) {
603
613
  if (isServer) {
604
614
  const e = getRequestEvent();
605
- e && (e.response = Response.redirect(resolvedTo, 302));
615
+ e && (e.response = new Response(null, {
616
+ status: 302,
617
+ headers: {
618
+ Location: resolvedTo
619
+ }
620
+ }));
606
621
  setSource({
607
622
  value: resolvedTo,
608
623
  replace,
@@ -758,7 +773,7 @@ function createRouterContext(integration, getBranches, base = "") {
758
773
  let actionRef = evt.submitter && evt.submitter.getAttribute("formaction") || evt.target.action;
759
774
  if (actionRef && actionRef.startsWith("action:")) {
760
775
  const data = new FormData(evt.target);
761
- actions.get(actionRef.slice(7))(data);
776
+ actions.get(actionRef).call(router, data);
762
777
  evt.preventDefault();
763
778
  }
764
779
  }
@@ -794,16 +809,7 @@ function createRouterContext(integration, getBranches, base = "") {
794
809
  }
795
810
  submissions = initFromFlash(location.query);
796
811
  }
797
- return {
798
- base: baseRoute,
799
- location,
800
- isRouting,
801
- renderPath,
802
- parsePath,
803
- navigatorFactory,
804
- beforeLeave,
805
- submissions: createSignal(submissions)
806
- };
812
+ return router;
807
813
  }
808
814
  function createRouteContext(router, parent, outlet, match, params) {
809
815
  const {
@@ -850,7 +856,7 @@ const Router = props => {
850
856
  base
851
857
  } = props;
852
858
  const integration = source || (isServer ? staticIntegration({
853
- value: url || (e = getRequestEvent()) && e.request.url || ""
859
+ value: url || (e = getRequestEvent()) && getPath(e.request.url) || ""
854
860
  }) : pathIntegration());
855
861
  const routeDefs = children(() => props.children);
856
862
  const branches = createMemo(() => createBranches(props.root ? {
@@ -870,6 +876,10 @@ const Router = props => {
870
876
  }
871
877
  });
872
878
  };
879
+ function getPath(url) {
880
+ const u = new URL(url);
881
+ return u.pathname + u.search;
882
+ }
873
883
  function Routes(props) {
874
884
  const matches = createMemo(() => getRouteMatches(props.branches, props.routerState.location.pathname));
875
885
  const params = createMemoObject(() => {
@@ -1006,8 +1016,8 @@ function Navigate(props) {
1006
1016
  /**
1007
1017
  * This is mock of the eventual Solid 2.0 primitive. It is not fully featured.
1008
1018
  */
1009
- function createAsync(fn) {
1010
- const [resource] = createResource(() => subFetch(fn), v => v);
1019
+ function createAsync(fn, options) {
1020
+ const [resource] = createResource(() => subFetch(fn), v => v, options);
1011
1021
  return () => resource();
1012
1022
  }
1013
1023
 
@@ -1102,7 +1112,7 @@ function cache(fn, name, options) {
1102
1112
  version && cached[3].add(version);
1103
1113
  if (cached[2] === "preload" && intent !== "preload") {
1104
1114
  cached[0] = now;
1105
- cached[1] = "then" in cached[1] ? cached[1].then(handleResponse) : handleResponse(cached[1]);
1115
+ cached[1] = "then" in cached[1] ? cached[1].then(handleResponse, handleResponse) : handleResponse(cached[1]);
1106
1116
  cached[2] = intent;
1107
1117
  }
1108
1118
  if (!isServer && intent === "navigate") {
@@ -1119,7 +1129,7 @@ function cache(fn, name, options) {
1119
1129
  sharedConfig.context && sharedConfig.context.serialize(key, res);
1120
1130
  }
1121
1131
  if (intent !== "preload") {
1122
- res = "then" in res ? res.then(handleResponse) : handleResponse(res);
1132
+ res = "then" in res ? res.then(handleResponse, handleResponse) : handleResponse(res);
1123
1133
  }
1124
1134
  if (cached) {
1125
1135
  cached[0] = now;
@@ -1131,23 +1141,23 @@ function cache(fn, name, options) {
1131
1141
  }
1132
1142
  } else cache.set(key, cached = [now, res, intent, new Set(version ? [version] : [])]);
1133
1143
  return res;
1134
- function handleRedirect(response) {
1135
- startTransition(() => {
1136
- let url = response.headers.get(LocationHeader);
1137
- if (url && url.startsWith("/")) {
1138
- navigate(url, {
1139
- replace: true
1140
- });
1141
- } else if (!isServer && url) {
1142
- window.location.href = url;
1143
- }
1144
- });
1145
- }
1146
1144
  function handleResponse(v) {
1147
1145
  if (v instanceof Response && redirectStatusCodes.has(v.status)) {
1148
- if (navigate) isServer ? handleRedirect(v) : setTimeout(() => handleRedirect(v), 0);
1146
+ if (navigate) {
1147
+ startTransition(() => {
1148
+ let url = v.headers.get(LocationHeader);
1149
+ if (url && url.startsWith("/")) {
1150
+ navigate(url, {
1151
+ replace: true
1152
+ });
1153
+ } else if (!isServer && url) {
1154
+ window.location.href = url;
1155
+ }
1156
+ });
1157
+ }
1149
1158
  return;
1150
1159
  }
1160
+ if (v instanceof Error) throw v;
1151
1161
  if (isServer) return v;
1152
1162
  setStore(key, reconcile(v, options));
1153
1163
  return store[key];
@@ -1195,6 +1205,13 @@ function action(fn, name) {
1195
1205
  const [result, setResult] = createSignal();
1196
1206
  let submission;
1197
1207
  const router = this;
1208
+ async function handler(res) {
1209
+ const data = await handleResponse(res, router.navigatorFactory());
1210
+ data ? setResult({
1211
+ data
1212
+ }) : submission.clear();
1213
+ return data;
1214
+ }
1198
1215
  router.submissions[1](s => [...s, submission = {
1199
1216
  input: variables,
1200
1217
  url,
@@ -1210,36 +1227,14 @@ function action(fn, name) {
1210
1227
  retry() {
1211
1228
  setResult(undefined);
1212
1229
  const p = fn(variables);
1213
- p.then(async data => {
1214
- const keys = handleResponse(data, router.navigatorFactory());
1215
- await revalidate(keys);
1216
- data ? setResult({
1217
- data
1218
- }) : submission.clear();
1219
- return data;
1220
- }).catch(error => {
1221
- setResult({
1222
- data: error
1223
- });
1224
- });
1230
+ p.then(handler, handler);
1225
1231
  return p;
1226
1232
  }
1227
1233
  }]);
1228
- p.then(async data => {
1229
- const keys = handleResponse(data, router.navigatorFactory());
1230
- await revalidate(keys);
1231
- data ? setResult({
1232
- data
1233
- }) : submission.clear();
1234
- return data;
1235
- }).catch(error => {
1236
- setResult({
1237
- data: error
1238
- });
1239
- });
1234
+ p.then(handler, handler);
1240
1235
  return p;
1241
1236
  }
1242
- const url = fn.url || `action:${name}` || !isServer ? `action:${fn.name}` : "";
1237
+ const url = fn.url || name && `action:${name}` || (!isServer ? `action:${fn.name}` : "");
1243
1238
  mutate.toString = () => {
1244
1239
  if (!url) throw new Error("Client Actions need explicit names if server rendered");
1245
1240
  return url;
@@ -1247,7 +1242,8 @@ function action(fn, name) {
1247
1242
  if (!isServer) registerAction(url, mutate);
1248
1243
  return mutate;
1249
1244
  }
1250
- function handleResponse(response, navigate) {
1245
+ async function handleResponse(response, navigate) {
1246
+ let data;
1251
1247
  if (response instanceof Response && redirectStatusCodes.has(response.status)) {
1252
1248
  const locationUrl = response.headers.get("Location") || "/";
1253
1249
  if (locationUrl.startsWith("http")) {
@@ -1255,9 +1251,28 @@ function handleResponse(response, navigate) {
1255
1251
  } else {
1256
1252
  navigate(locationUrl);
1257
1253
  }
1254
+ } else data = response;
1255
+ // TODO: handle keys
1256
+ await revalidate();
1257
+ return data;
1258
+ }
1259
+
1260
+ function redirect(url, init = 302) {
1261
+ let responseInit = init;
1262
+ if (typeof responseInit === "number") {
1263
+ responseInit = {
1264
+ status: responseInit
1265
+ };
1266
+ } else if (typeof responseInit.status === "undefined") {
1267
+ responseInit.status = 302;
1258
1268
  }
1259
- // return keys
1260
- return;
1269
+ const headers = new Headers(responseInit.headers);
1270
+ headers.set("Location", url);
1271
+ const response = new Response(null, {
1272
+ ...responseInit,
1273
+ headers: headers
1274
+ });
1275
+ return response;
1261
1276
  }
1262
1277
 
1263
- export { A, A as Link, A as NavLink, Navigate, Route, Router, mergeSearchString as _mergeSearchString, action, cache, createAsync, createBeforeLeave, createIntegration, createMemoryHistory, hashIntegration, memoryIntegration, normalizeIntegration, pathIntegration, revalidate, staticIntegration, useBeforeLeave, useHref, useIsRouting, useLocation, useMatch, useNavigate, useParams, useResolvedPath, useSearchParams, useSubmission, useSubmissions };
1278
+ export { A, A as Link, A as NavLink, Navigate, Route, Router, mergeSearchString as _mergeSearchString, action, cache, createAsync, createBeforeLeave, createIntegration, createMemoryHistory, hashIntegration, memoryIntegration, normalizeIntegration, pathIntegration, redirect, revalidate, staticIntegration, useBeforeLeave, useHref, useIsRouting, useLocation, useMatch, useNavigate, useParams, useResolvedPath, useSearchParams, useSubmission, useSubmissions };
package/dist/routing.js CHANGED
@@ -217,6 +217,16 @@ export function createRouterContext(integration, getBranches, base = "") {
217
217
  return resolvePath(basePath, to);
218
218
  }
219
219
  };
220
+ const router = {
221
+ base: baseRoute,
222
+ location,
223
+ isRouting,
224
+ renderPath,
225
+ parsePath,
226
+ navigatorFactory,
227
+ beforeLeave,
228
+ submissions: createSignal(submissions)
229
+ };
220
230
  function navigateFromRoute(route, to, options) {
221
231
  // Untrack in case someone navigates in an effect - don't want to track `reference` or route paths
222
232
  untrack(() => {
@@ -249,7 +259,8 @@ export function createRouterContext(integration, getBranches, base = "") {
249
259
  if (resolvedTo !== current || nextState !== state()) {
250
260
  if (isServer) {
251
261
  const e = getRequestEvent();
252
- e && (e.response = Response.redirect(resolvedTo, 302));
262
+ e &&
263
+ (e.response = new Response(null, { status: 302, headers: { Location: resolvedTo } }));
253
264
  setSource({ value: resolvedTo, replace, scroll, state: nextState });
254
265
  }
255
266
  else if (beforeLeave.confirm(resolvedTo, options)) {
@@ -413,7 +424,7 @@ export function createRouterContext(integration, getBranches, base = "") {
413
424
  let actionRef = (evt.submitter && evt.submitter.getAttribute("formaction")) || evt.target.action;
414
425
  if (actionRef && actionRef.startsWith("action:")) {
415
426
  const data = new FormData(evt.target);
416
- actions.get(actionRef.slice(7))(data);
427
+ actions.get(actionRef).call(router, data);
417
428
  evt.preventDefault();
418
429
  }
419
430
  }
@@ -451,16 +462,7 @@ export function createRouterContext(integration, getBranches, base = "") {
451
462
  }
452
463
  submissions = initFromFlash(location.query);
453
464
  }
454
- return {
455
- base: baseRoute,
456
- location,
457
- isRouting,
458
- renderPath,
459
- parsePath,
460
- navigatorFactory,
461
- beforeLeave,
462
- submissions: createSignal(submissions)
463
- };
465
+ return router;
464
466
  }
465
467
  export function createRouteContext(router, parent, outlet, match, params) {
466
468
  const { base, location } = router;
package/package.json CHANGED
@@ -6,7 +6,7 @@
6
6
  "Ryan Turnquist"
7
7
  ],
8
8
  "license": "MIT",
9
- "version": "0.10.0-beta.1",
9
+ "version": "0.10.0-beta.2",
10
10
  "homepage": "https://github.com/solidjs/solid-router#readme",
11
11
  "repository": {
12
12
  "type": "git",