@solidjs/router 0.13.6 → 0.14.0

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 CHANGED
@@ -10,7 +10,7 @@ A router lets you change your view based on the URL in the browser. This allows
10
10
 
11
11
  Solid Router is a universal router for SolidJS - it works whether you're rendering on the client or on the server. It was inspired by and combines paradigms of React Router and the Ember Router. Routes can be defined directly in your app's template using JSX, but you can also pass your route configuration directly as an object. It also supports nested routing, so navigation can change a part of a component, rather than completely replacing it.
12
12
 
13
- It supports all of Solid's SSR methods and has Solid's transitions baked in, so use it freely with suspense, resources, and lazy components. Solid Router also allows you to define a load function that loads parallel to the routes ([render-as-you-fetch](https://epicreact.dev/render-as-you-fetch/)).
13
+ It supports all of Solid's SSR methods and has Solid's transitions baked in, so use it freely with suspense, resources, and lazy components. Solid Router also allows you to define a preload function that loads parallel to the routes ([render-as-you-fetch](https://epicreact.dev/render-as-you-fetch/)).
14
14
 
15
15
  - [Getting Started](#getting-started)
16
16
  - [Set Up the Router](#set-up-the-router)
@@ -380,11 +380,11 @@ You can nest indefinitely - just remember that only leaf nodes will become their
380
380
  </Route>
381
381
  ```
382
382
 
383
- ## Load Functions
383
+ ## Preload Functions
384
384
 
385
- Even with smart caches it is possible that we have waterfalls both with view logic and with lazy loaded code. With load functions, we can instead start fetching the data parallel to loading the route, so we can use the data as soon as possible. The load function is called when the Route is loaded or eagerly when links are hovered.
385
+ Even with smart caches it is possible that we have waterfalls both with view logic and with lazy loaded code. With preload functions, we can instead start fetching the data parallel to loading the route, so we can use the data as soon as possible. The preload function is called when the Route is loaded or eagerly when links are hovered.
386
386
 
387
- As its only argument, the load function is passed an object that you can use to access route information:
387
+ As its only argument, the preload function is passed an object that you can use to access route information:
388
388
 
389
389
  ```js
390
390
  import { lazy } from "solid-js";
@@ -392,13 +392,13 @@ import { Route } from "@solidjs/router";
392
392
 
393
393
  const User = lazy(() => import("./pages/users/[id].js"));
394
394
 
395
- // load function
396
- function loadUser({params, location}) {
397
- // do loading
395
+ // preload function
396
+ function preloadUser({params, location}) {
397
+ // do preloading
398
398
  }
399
399
 
400
400
  // Pass it in the route definition
401
- <Route path="/users/:id" component={User} load={loadUser} />;
401
+ <Route path="/users/:id" component={User} preload={preloadUser} />;
402
402
  ```
403
403
 
404
404
  | key | type | description |
@@ -408,24 +408,24 @@ function loadUser({params, location}) {
408
408
  | intent | `"initial", "navigate", "native", "preload"` | Indicates why this function is being called. <ul><li>"initial" - the route is being initially shown (ie page load)</li><li>"native" - navigate originated from the browser (eg back/forward)</li><li>"navigate" - navigate originated from the router (eg call to navigate or anchor clicked)</li><li>"preload" - not navigating, just preloading (eg link hover)</li></ul> |
409
409
 
410
410
 
411
- A common pattern is to export the load function and data wrappers that corresponds to a route in a dedicated `route.data.js` file. This way, the data function can be imported without loading anything else.
411
+ A common pattern is to export the preload function and data wrappers that corresponds to a route in a dedicated `route.data.js` file. This way, the data function can be imported without loading anything else.
412
412
 
413
413
  ```js
414
414
  import { lazy } from "solid-js";
415
415
  import { Route } from "@solidjs/router";
416
- import loadUser from "./pages/users/[id].data.js";
416
+ import preloadUser from "./pages/users/[id].data.js";
417
417
  const User = lazy(() => import("/pages/users/[id].js"));
418
418
 
419
419
  // In the Route definition
420
- <Route path="/users/:id" component={User} load={loadUser} />;
420
+ <Route path="/users/:id" component={User} preload={preloadUser} />;
421
421
  ```
422
422
 
423
- The return value of the `load` function is passed to the page component when called at anytime other than `"preload"`, so you can initialize things in there, or alternatively use our new Data APIs:
423
+ The return value of the `preload` function is passed to the page component when called at anytime other than `"preload"` intent, so you can initialize things in there, or alternatively use our new Data APIs:
424
424
 
425
425
 
426
426
  ## Data APIs
427
427
 
428
- Keep in mind these are completely optional. To use but showcase the power of our load mechanism.
428
+ Keep in mind these are completely optional. To use but showcase the power of our preload mechanism.
429
429
 
430
430
  ### `cache`
431
431
 
@@ -441,11 +441,11 @@ It is expected that the arguments to the cache function are serializable.
441
441
  This cache accomplishes the following:
442
442
 
443
443
  1. It does just deduping on the server for the lifetime of the request.
444
- 2. It does preload cache in the browser which lasts 10 seconds. When a route is preloaded on hover or when load is called when entering a route it will make sure to dedupe calls.
444
+ 2. It does preload cache in the browser which lasts 5 seconds. When a route is preloaded on hover or when preload is called when entering a route it will make sure to dedupe calls.
445
445
  3. We have a reactive refetch mechanism based on key. So we can tell routes that aren't new to retrigger on action revalidation.
446
446
  4. It will serve as a back/forward cache for browser navigation up to 5 mins. Any user based navigation or link click bypasses it. Revalidation or new fetch updates the cache.
447
447
 
448
- Using it with load function might look like:
448
+ Using it with preload function might look like:
449
449
 
450
450
  ```js
451
451
  import { lazy } from "solid-js";
@@ -454,13 +454,13 @@ import { getUser } from ... // the cache function
454
454
 
455
455
  const User = lazy(() => import("./pages/users/[id].js"));
456
456
 
457
- // load function
458
- function loadUser({params, location}) {
457
+ // preload function
458
+ function preloadUser({params, location}) {
459
459
  void getUser(params.id)
460
460
  }
461
461
 
462
462
  // Pass it in the route definition
463
- <Route path="/users/:id" component={User} load={loadUser} />;
463
+ <Route path="/users/:id" component={User} preload={preloadUser} />;
464
464
  ```
465
465
 
466
466
  Inside your page component you:
@@ -770,7 +770,7 @@ The Component for defining Routes:
770
770
  | component | `Component` | Component that will be rendered for the matched segment |
771
771
  | matchFilters | `MatchFilters` | Additional constraints for matching against the route |
772
772
  | children | `JSX.Element` | Nested `<Route>` definitions |
773
- | load | `RouteLoadFunc` | Function called during preload or when the route is navigated to. |
773
+ | preload | `RoutePreloadFunc` | Function called during preload or when the route is navigated to. |
774
774
 
775
775
  ## Router Primitives
776
776
 
@@ -929,7 +929,7 @@ Related without Outlet component it has to be passed in manually. At which point
929
929
 
930
930
  ### `data` functions & `useRouteData`
931
931
 
932
- These have been replaced by a load mechanism. This allows link hover preloads (as the load function can be run as much as wanted without worry about reactivity). It support deduping/cache APIs which give more control over how things are cached. It also addresses TS issues with getting the right types in the Component without `typeof` checks.
932
+ These have been replaced by a preload mechanism. This allows link hover preloads (as the preload function can be run as much as wanted without worry about reactivity). It support deduping/cache APIs which give more control over how things are cached. It also addresses TS issues with getting the right types in the Component without `typeof` checks.
933
933
 
934
934
  That being said you can reproduce the old pattern largely by turning off preloads at the router level and then injecting your own Context:
935
935
 
@@ -939,15 +939,15 @@ import { Route } from "@solidjs/router";
939
939
 
940
940
  const User = lazy(() => import("./pages/users/[id].js"));
941
941
 
942
- // load function
943
- function loadUser({params, location}) {
942
+ // preload function
943
+ function preloadUser({params, location}) {
944
944
  const [user] = createResource(() => params.id, fetchUser);
945
945
  return user;
946
946
  }
947
947
 
948
948
  // Pass it in the route definition
949
949
  <Router preload={false}>
950
- <Route path="/users/:id" component={User} load={loadUser} />
950
+ <Route path="/users/:id" component={User} preload={preloadUser} />
951
951
  </Router>
952
952
  ```
953
953
 
@@ -1,13 +1,13 @@
1
1
  import { JSX } from "solid-js";
2
- import type { Submission, SubmissionStub } from "../types.js";
3
- export type Action<T extends Array<any>, U> = (T extends [FormData] | [] ? JSX.SerializableAttributeValue : unknown) & ((...vars: T) => Promise<U>) & {
2
+ import type { Submission, SubmissionStub, NarrowResponse } from "../types.js";
3
+ export type Action<T extends Array<any>, U> = (T extends [FormData] | [] ? JSX.SerializableAttributeValue : unknown) & ((...vars: T) => Promise<NarrowResponse<U>>) & {
4
4
  url: string;
5
- with<A extends any[], B extends any[]>(this: (this: any, ...args: [...A, ...B]) => Promise<U>, ...args: A): Action<B, U>;
5
+ with<A extends any[], B extends any[]>(this: (this: any, ...args: [...A, ...B]) => Promise<NarrowResponse<U>>, ...args: A): Action<B, U>;
6
6
  };
7
7
  export declare const actions: Map<string, Action<any, any>>;
8
8
  export declare function useSubmissions<T extends Array<any>, U>(fn: Action<T, U>, filter?: (arg: T) => boolean): Submission<T, U>[] & {
9
9
  pending: boolean;
10
10
  };
11
11
  export declare function useSubmission<T extends Array<any>, U>(fn: Action<T, U>, filter?: (arg: T) => boolean): Submission<T, U> | SubmissionStub;
12
- export declare function useAction<T extends Array<any>, U>(action: Action<T, U>): (...args: Parameters<Action<T, U>>) => Promise<U>;
12
+ export declare function useAction<T extends Array<any>, U>(action: Action<T, U>): (...args: Parameters<Action<T, U>>) => Promise<NarrowResponse<U>>;
13
13
  export declare function action<T extends Array<any>, U = void>(fn: (...args: T) => Promise<U>, name?: string): Action<T, U>;
@@ -1,9 +1,9 @@
1
- import { CacheEntry } from "../types.js";
1
+ import type { CacheEntry, NarrowResponse } from "../types.js";
2
2
  export declare function revalidate(key?: string | string[] | void, force?: boolean): Promise<void>;
3
3
  export declare function cacheKeyOp(key: string | string[] | void, fn: (cacheEntry: CacheEntry) => void): void;
4
4
  export type CachedFunction<T extends (...args: any) => any> = T extends (...args: infer A) => infer R ? ([] extends {
5
5
  [K in keyof A]-?: A[K];
6
- } ? (...args: never[]) => R : T) & {
6
+ } ? (...args: never[]) => R extends Promise<infer P> ? Promise<NarrowResponse<P>> : NarrowResponse<R> : (...args: A) => R extends Promise<infer P> ? Promise<NarrowResponse<P>> : NarrowResponse<R>) & {
7
7
  keyFor: (...args: A) => string;
8
8
  key: string;
9
9
  } : never;
@@ -1,6 +1,6 @@
1
1
  import { createSignal, getListener, getOwner, onCleanup, sharedConfig, startTransition } from "solid-js";
2
2
  import { getRequestEvent, isServer } from "solid-js/web";
3
- import { useNavigate, getIntent, getInLoadFn } from "../routing.js";
3
+ import { useNavigate, getIntent, getInPreloadFn } from "../routing.js";
4
4
  const LocationHeader = "Location";
5
5
  const PRELOAD_TIMEOUT = 5000;
6
6
  const CACHE_TIMEOUT = 180000;
@@ -47,7 +47,7 @@ export function cache(fn, name) {
47
47
  const cachedFn = ((...args) => {
48
48
  const cache = getCache();
49
49
  const intent = getIntent();
50
- const inLoadFn = getInLoadFn();
50
+ const inPreloadFn = getInPreloadFn();
51
51
  const owner = getOwner();
52
52
  const navigate = owner ? useNavigate() : undefined;
53
53
  const now = Date.now();
@@ -94,7 +94,7 @@ export function cache(fn, name) {
94
94
  : handleResponse(false)(cached[1]);
95
95
  !isServer && intent === "navigate" && startTransition(() => cached[3][1](cached[0])); // update version
96
96
  }
97
- inLoadFn && "then" in res && res.catch(() => { });
97
+ inPreloadFn && "then" in res && res.catch(() => { });
98
98
  return res;
99
99
  }
100
100
  let res = !isServer && sharedConfig.context && sharedConfig.has(key)
@@ -125,7 +125,7 @@ export function cache(fn, name) {
125
125
  ? res.then(handleResponse(false), handleResponse(true))
126
126
  : handleResponse(false)(res);
127
127
  }
128
- inLoadFn && "then" in res && res.catch(() => { });
128
+ inPreloadFn && "then" in res && res.catch(() => { });
129
129
  // serialize on server
130
130
  if (isServer &&
131
131
  sharedConfig.context &&
@@ -111,10 +111,10 @@ export function setupNativeEvents(preload = true, explicitLinks = false, actionB
111
111
  const handler = actions.get(actionRef);
112
112
  if (handler) {
113
113
  evt.preventDefault();
114
- const data = new FormData(evt.target);
115
- if (evt.submitter && evt.submitter.name)
116
- data.append(evt.submitter.name, evt.submitter.value);
117
- handler.call({ r: router, f: evt.target }, data);
114
+ const data = new FormData(evt.target, evt.submitter);
115
+ handler.call({ r: router, f: evt.target }, evt.target.enctype === "multipart/form-data"
116
+ ? data
117
+ : new URLSearchParams(data));
118
118
  }
119
119
  }
120
120
  // ensure delegated event run first
@@ -1,6 +1,4 @@
1
- export type RouterResponseInit = Omit<ResponseInit, "body"> & {
2
- revalidate?: string | string[];
3
- };
4
- export declare function redirect(url: string, init?: number | RouterResponseInit): never;
5
- export declare function reload(init?: RouterResponseInit): never;
6
- export declare function json<T>(data: T, init?: RouterResponseInit): T;
1
+ import type { RouterResponseInit, CustomResponse } from "../types";
2
+ export declare function redirect(url: string, init?: number | RouterResponseInit): CustomResponse<never>;
3
+ export declare function reload(init?: RouterResponseInit): CustomResponse<never>;
4
+ export declare function json<T>(data: T, init?: RouterResponseInit): CustomResponse<T>;
package/dist/index.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  export * from "./routers/index.js";
2
2
  export * from "./components.jsx";
3
3
  export * from "./lifecycle.js";
4
- export { useHref, useIsRouting, useLocation, useMatch, useCurrentMatches, useNavigate, useParams, useResolvedPath, useSearchParams, useBeforeLeave, } from "./routing.js";
4
+ export { useHref, useIsRouting, useLocation, useMatch, useCurrentMatches, useNavigate, useParams, useResolvedPath, useSearchParams, useBeforeLeave, usePreloadRoute } from "./routing.js";
5
5
  export { mergeSearchString as _mergeSearchString } from "./utils.js";
6
6
  export * from "./data/index.js";
7
- export type { Location, LocationChange, MatchFilter, MatchFilters, NavigateOptions, Navigator, OutputMatch, Params, PathMatch, RouteSectionProps, RouteLoadFunc, RouteLoadFuncArgs, RouteDefinition, RouteDescription, RouteMatch, RouterIntegration, RouterUtils, SetParams, BeforeLeaveEventArgs } from "./types.js";
7
+ export type { Location, LocationChange, MatchFilter, MatchFilters, NavigateOptions, Navigator, OutputMatch, Params, PathMatch, RouteSectionProps, RoutePreloadFunc, RoutePreloadFuncArgs, RouteDefinition, RouteDescription, RouteMatch, RouterIntegration, RouterUtils, SetParams, BeforeLeaveEventArgs, RouteLoadFunc, RouteLoadFuncArgs, RouterResponseInit, CustomResponse } from "./types.js";
package/dist/index.js CHANGED
@@ -246,6 +246,7 @@ const useHref = to => {
246
246
  const useNavigate = () => useRouter().navigatorFactory();
247
247
  const useLocation = () => useRouter().location;
248
248
  const useIsRouting = () => useRouter().isRouting;
249
+ const usePreloadRoute = () => useRouter().preloadRoute;
249
250
  const useMatch = (path, matchFilters) => {
250
251
  const location = useLocation();
251
252
  const matchers = createMemo(() => expandOptionals(path()).map(path => createMatcher(path, undefined, matchFilters)));
@@ -282,6 +283,7 @@ const useBeforeLeave = listener => {
282
283
  function createRoutes(routeDef, base = "") {
283
284
  const {
284
285
  component,
286
+ preload,
285
287
  load,
286
288
  children,
287
289
  info
@@ -290,7 +292,7 @@ function createRoutes(routeDef, base = "") {
290
292
  const shared = {
291
293
  key: routeDef,
292
294
  component,
293
- load,
295
+ preload: preload || load,
294
296
  info
295
297
  };
296
298
  return asArray(routeDef.path).reduce((acc, originalPath) => {
@@ -407,12 +409,12 @@ let intent;
407
409
  function getIntent() {
408
410
  return intent;
409
411
  }
410
- let inLoadFn = false;
411
- function getInLoadFn() {
412
- return inLoadFn;
412
+ let inPreloadFn = false;
413
+ function getInPreloadFn() {
414
+ return inPreloadFn;
413
415
  }
414
- function setInLoadFn(value) {
415
- inLoadFn = value;
416
+ function setInPreloadFn(value) {
417
+ inPreloadFn = value;
416
418
  }
417
419
  function createRouterContext(integration, branches, getContext, options = {}) {
418
420
  const {
@@ -593,10 +595,10 @@ function createRouterContext(integration, branches, getContext, options = {}) {
593
595
  } = matches[match];
594
596
  route.component && route.component.preload && route.component.preload();
595
597
  const {
596
- load
598
+ preload
597
599
  } = route;
598
- inLoadFn = true;
599
- options.preloadData && load && runWithOwner(getContext(), () => load({
600
+ inPreloadFn = true;
601
+ options.preloadData && preload && runWithOwner(getContext(), () => preload({
600
602
  params,
601
603
  location: {
602
604
  pathname: url.pathname,
@@ -608,7 +610,7 @@ function createRouterContext(integration, branches, getContext, options = {}) {
608
610
  },
609
611
  intent: "preload"
610
612
  }));
611
- inLoadFn = false;
613
+ inPreloadFn = false;
612
614
  }
613
615
  intent = prevIntent;
614
616
  }
@@ -626,17 +628,17 @@ function createRouteContext(router, parent, outlet, match) {
626
628
  const {
627
629
  pattern,
628
630
  component,
629
- load
631
+ preload
630
632
  } = match().route;
631
633
  const path = createMemo(() => match().path);
632
634
  component && component.preload && component.preload();
633
- inLoadFn = true;
634
- const data = load ? load({
635
+ inPreloadFn = true;
636
+ const data = preload ? preload({
635
637
  params,
636
638
  location,
637
639
  intent: intent || "initial"
638
640
  }) : undefined;
639
- inLoadFn = false;
641
+ inPreloadFn = false;
640
642
  const route = {
641
643
  parent,
642
644
  pattern,
@@ -677,8 +679,8 @@ const createRouterComponent = router => props => {
677
679
  get root() {
678
680
  return props.root;
679
681
  },
680
- get load() {
681
- return props.rootLoad;
682
+ get preload() {
683
+ return props.rootPreload || props.rootLoad;
682
684
  },
683
685
  get children() {
684
686
  return [memo(() => (context = getOwner()) && null), createComponent$1(Routes, {
@@ -695,14 +697,14 @@ const createRouterComponent = router => props => {
695
697
  function Root(props) {
696
698
  const location = props.routerState.location;
697
699
  const params = props.routerState.params;
698
- const data = createMemo(() => props.load && untrack(() => {
699
- setInLoadFn(true);
700
- props.load({
700
+ const data = createMemo(() => props.preload && untrack(() => {
701
+ setInPreloadFn(true);
702
+ props.preload({
701
703
  params,
702
704
  location,
703
705
  intent: getIntent() || "initial"
704
706
  });
705
- setInLoadFn(false);
707
+ setInPreloadFn(false);
706
708
  }));
707
709
  return createComponent$1(Show, {
708
710
  get when() {
@@ -807,7 +809,7 @@ function dataOnly(event, routerState, branches) {
807
809
  route,
808
810
  params
809
811
  } = matches[match];
810
- route.load && route.load({
812
+ route.preload && route.preload({
811
813
  params,
812
814
  location: routerState.location,
813
815
  intent: "preload"
@@ -922,7 +924,7 @@ function cache(fn, name) {
922
924
  const cachedFn = (...args) => {
923
925
  const cache = getCache();
924
926
  const intent = getIntent();
925
- const inLoadFn = getInLoadFn();
927
+ const inPreloadFn = getInPreloadFn();
926
928
  const owner = getOwner();
927
929
  const navigate = owner ? useNavigate() : undefined;
928
930
  const now = Date.now();
@@ -960,7 +962,7 @@ function cache(fn, name) {
960
962
  res = "then" in cached[1] ? cached[1].then(handleResponse(false), handleResponse(true)) : handleResponse(false)(cached[1]);
961
963
  !isServer && intent === "navigate" && startTransition(() => cached[3][1](cached[0])); // update version
962
964
  }
963
- inLoadFn && "then" in res && res.catch(() => {});
965
+ inPreloadFn && "then" in res && res.catch(() => {});
964
966
  return res;
965
967
  }
966
968
  let res = !isServer && sharedConfig.context && sharedConfig.has(key) ? sharedConfig.load(key) // hydrating
@@ -985,7 +987,7 @@ function cache(fn, name) {
985
987
  if (intent !== "preload") {
986
988
  res = "then" in res ? res.then(handleResponse(false), handleResponse(true)) : handleResponse(false)(res);
987
989
  }
988
- inLoadFn && "then" in res && res.catch(() => {});
990
+ inPreloadFn && "then" in res && res.catch(() => {});
989
991
  // serialize on server
990
992
  if (isServer && sharedConfig.context && sharedConfig.context.async && !sharedConfig.context.noHydrate) {
991
993
  const e = getRequestEvent();
@@ -1277,12 +1279,11 @@ function setupNativeEvents(preload = true, explicitLinks = false, actionBase = "
1277
1279
  const handler = actions.get(actionRef);
1278
1280
  if (handler) {
1279
1281
  evt.preventDefault();
1280
- const data = new FormData(evt.target);
1281
- if (evt.submitter && evt.submitter.name) data.append(evt.submitter.name, evt.submitter.value);
1282
+ const data = new FormData(evt.target, evt.submitter);
1282
1283
  handler.call({
1283
1284
  r: router,
1284
1285
  f: evt.target
1285
- }, data);
1286
+ }, evt.target.enctype === "multipart/form-data" ? data : new URLSearchParams(data));
1286
1287
  }
1287
1288
  }
1288
1289
 
@@ -1312,7 +1313,7 @@ function setupNativeEvents(preload = true, explicitLinks = false, actionBase = "
1312
1313
  function Router(props) {
1313
1314
  if (isServer) return StaticRouter(props);
1314
1315
  const getSource = () => {
1315
- const url = window.location.pathname + window.location.search;
1316
+ const url = window.location.pathname.replace(/^\/+/, "/") + window.location.search;
1316
1317
  return {
1317
1318
  value: props.transformUrl ? props.transformUrl(url) + window.location.hash : url + window.location.hash,
1318
1319
  state: window.history.state
@@ -1643,4 +1644,4 @@ function json(data, init = {}) {
1643
1644
  return response;
1644
1645
  }
1645
1646
 
1646
- export { A, HashRouter, MemoryRouter, Navigate, Route, Router, StaticRouter, mergeSearchString as _mergeSearchString, action, cache, createAsync, createAsyncStore, createBeforeLeave, createMemoryHistory, createRouter, json, keepDepth, notifyIfNotBlocked, redirect, reload, revalidate, saveCurrentDepth, useAction, useBeforeLeave, useCurrentMatches, useHref, useIsRouting, useLocation, useMatch, useNavigate, useParams, useResolvedPath, useSearchParams, useSubmission, useSubmissions };
1647
+ export { A, HashRouter, MemoryRouter, Navigate, Route, Router, StaticRouter, mergeSearchString as _mergeSearchString, action, cache, createAsync, createAsyncStore, createBeforeLeave, createMemoryHistory, createRouter, json, keepDepth, notifyIfNotBlocked, redirect, reload, revalidate, saveCurrentDepth, useAction, useBeforeLeave, useCurrentMatches, useHref, useIsRouting, useLocation, useMatch, useNavigate, useParams, usePreloadRoute, useResolvedPath, useSearchParams, useSubmission, useSubmissions };
package/dist/index.jsx CHANGED
@@ -1,6 +1,6 @@
1
1
  export * from "./routers/index.js";
2
2
  export * from "./components.jsx";
3
3
  export * from "./lifecycle.js";
4
- export { useHref, useIsRouting, useLocation, useMatch, useCurrentMatches, useNavigate, useParams, useResolvedPath, useSearchParams, useBeforeLeave, } from "./routing.js";
4
+ export { useHref, useIsRouting, useLocation, useMatch, useCurrentMatches, useNavigate, useParams, useResolvedPath, useSearchParams, useBeforeLeave, usePreloadRoute } from "./routing.js";
5
5
  export { mergeSearchString as _mergeSearchString } from "./utils.js";
6
6
  export * from "./data/index.js";
@@ -7,7 +7,7 @@ export function Router(props) {
7
7
  if (isServer)
8
8
  return StaticRouter(props);
9
9
  const getSource = () => {
10
- const url = window.location.pathname + window.location.search;
10
+ const url = window.location.pathname.replace(/^\/+/, "/") + window.location.search;
11
11
  return {
12
12
  value: props.transformUrl ? props.transformUrl(url) + window.location.hash : url + window.location.hash,
13
13
  state: window.history.state
@@ -1,23 +1,27 @@
1
1
  import type { Component, JSX } from "solid-js";
2
- import type { MatchFilters, RouteLoadFunc, RouteDefinition, RouterIntegration, RouteSectionProps } from "../types.js";
2
+ import type { MatchFilters, RouteDefinition, RouterIntegration, RouteSectionProps, RoutePreloadFunc } from "../types.js";
3
3
  export type BaseRouterProps = {
4
4
  base?: string;
5
5
  /**
6
6
  * A component that wraps the content of every route.
7
7
  */
8
8
  root?: Component<RouteSectionProps>;
9
- rootLoad?: RouteLoadFunc;
9
+ rootPreload?: RoutePreloadFunc;
10
10
  singleFlight?: boolean;
11
11
  children?: JSX.Element | RouteDefinition | RouteDefinition[];
12
12
  transformUrl?: (url: string) => string;
13
+ /** @deprecated use rootPreload */
14
+ rootLoad?: RoutePreloadFunc;
13
15
  };
14
16
  export declare const createRouterComponent: (router: RouterIntegration) => (props: BaseRouterProps) => JSX.Element;
15
17
  export type RouteProps<S extends string, T = unknown> = {
16
18
  path?: S | S[];
17
19
  children?: JSX.Element;
18
- load?: RouteLoadFunc<T>;
20
+ preload?: RoutePreloadFunc<T>;
19
21
  matchFilters?: MatchFilters<S>;
20
22
  component?: Component<RouteSectionProps<T>>;
21
23
  info?: Record<string, any>;
24
+ /** @deprecated use preload */
25
+ load?: RoutePreloadFunc<T>;
22
26
  };
23
27
  export declare const Route: <S extends string, T = unknown>(props: RouteProps<S, T>) => JSX.Element;
@@ -1,7 +1,7 @@
1
1
  /*@refresh skip*/
2
2
  import { getRequestEvent, isServer } from "solid-js/web";
3
3
  import { children, createMemo, createRoot, getOwner, mergeProps, on, Show, untrack } from "solid-js";
4
- import { createBranches, createRouteContext, createRouterContext, getIntent, getRouteMatches, RouteContextObj, RouterContextObj, setInLoadFn } from "../routing.js";
4
+ import { createBranches, createRouteContext, createRouterContext, getIntent, getRouteMatches, RouteContextObj, RouterContextObj, setInPreloadFn } from "../routing.js";
5
5
  export const createRouterComponent = (router) => (props) => {
6
6
  const { base } = props;
7
7
  const routeDefs = children(() => props.children);
@@ -14,7 +14,7 @@ export const createRouterComponent = (router) => (props) => {
14
14
  });
15
15
  router.create && router.create(routerState);
16
16
  return (<RouterContextObj.Provider value={routerState}>
17
- <Root routerState={routerState} root={props.root} load={props.rootLoad}>
17
+ <Root routerState={routerState} root={props.root} preload={props.rootPreload || props.rootLoad}>
18
18
  {(context = getOwner()) && null}
19
19
  <Routes routerState={routerState} branches={branches()}/>
20
20
  </Root>
@@ -23,11 +23,11 @@ export const createRouterComponent = (router) => (props) => {
23
23
  function Root(props) {
24
24
  const location = props.routerState.location;
25
25
  const params = props.routerState.params;
26
- const data = createMemo(() => props.load &&
26
+ const data = createMemo(() => props.preload &&
27
27
  untrack(() => {
28
- setInLoadFn(true);
29
- props.load({ params, location, intent: getIntent() || "initial" });
30
- setInLoadFn(false);
28
+ setInPreloadFn(true);
29
+ props.preload({ params, location, intent: getIntent() || "initial" });
30
+ setInPreloadFn(false);
31
31
  }));
32
32
  return (<Show when={props.root} keyed fallback={props.children}>
33
33
  {Root => (<Root params={params} location={location} data={data()}>
@@ -105,8 +105,8 @@ function dataOnly(event, routerState, branches) {
105
105
  if (!prevMatches[match] || matches[match].route !== prevMatches[match].route)
106
106
  event.router.dataOnly = true;
107
107
  const { route, params } = matches[match];
108
- route.load &&
109
- route.load({
108
+ route.preload &&
109
+ route.preload({
110
110
  params,
111
111
  location: routerState.location,
112
112
  intent: "preload"
package/dist/routing.d.ts CHANGED
@@ -23,8 +23,8 @@ export declare function createBranches(routeDef: RouteDefinition | RouteDefiniti
23
23
  export declare function getRouteMatches(branches: Branch[], location: string): RouteMatch[];
24
24
  export declare function createLocation(path: Accessor<string>, state: Accessor<any>): Location;
25
25
  export declare function getIntent(): Intent | undefined;
26
- export declare function getInLoadFn(): boolean;
27
- export declare function setInLoadFn(value: boolean): void;
26
+ export declare function getInPreloadFn(): boolean;
27
+ export declare function setInPreloadFn(value: boolean): void;
28
28
  export declare function createRouterContext(integration: RouterIntegration, branches: () => Branch[], getContext?: () => any, options?: {
29
29
  base?: string;
30
30
  singleFlight?: boolean;
package/dist/routing.js CHANGED
@@ -59,12 +59,12 @@ export const useBeforeLeave = (listener) => {
59
59
  onCleanup(s);
60
60
  };
61
61
  export function createRoutes(routeDef, base = "") {
62
- const { component, load, children, info } = routeDef;
62
+ const { component, preload, load, children, info } = routeDef;
63
63
  const isLeaf = !children || (Array.isArray(children) && !children.length);
64
64
  const shared = {
65
65
  key: routeDef,
66
66
  component,
67
- load,
67
+ preload: preload || load,
68
68
  info
69
69
  };
70
70
  return asArray(routeDef.path).reduce((acc, originalPath) => {
@@ -186,12 +186,12 @@ let intent;
186
186
  export function getIntent() {
187
187
  return intent;
188
188
  }
189
- let inLoadFn = false;
190
- export function getInLoadFn() {
191
- return inLoadFn;
189
+ let inPreloadFn = false;
190
+ export function getInPreloadFn() {
191
+ return inPreloadFn;
192
192
  }
193
- export function setInLoadFn(value) {
194
- inLoadFn = value;
193
+ export function setInPreloadFn(value) {
194
+ inPreloadFn = value;
195
195
  }
196
196
  export function createRouterContext(integration, branches, getContext, options = {}) {
197
197
  const { signal: [source, setSource], utils = {} } = integration;
@@ -350,11 +350,11 @@ export function createRouterContext(integration, branches, getContext, options =
350
350
  route.component &&
351
351
  route.component.preload &&
352
352
  route.component.preload();
353
- const { load } = route;
354
- inLoadFn = true;
353
+ const { preload } = route;
354
+ inPreloadFn = true;
355
355
  options.preloadData &&
356
- load &&
357
- runWithOwner(getContext(), () => load({
356
+ preload &&
357
+ runWithOwner(getContext(), () => preload({
358
358
  params,
359
359
  location: {
360
360
  pathname: url.pathname,
@@ -366,7 +366,7 @@ export function createRouterContext(integration, branches, getContext, options =
366
366
  },
367
367
  intent: "preload"
368
368
  }));
369
- inLoadFn = false;
369
+ inPreloadFn = false;
370
370
  }
371
371
  intent = prevIntent;
372
372
  }
@@ -377,14 +377,14 @@ export function createRouterContext(integration, branches, getContext, options =
377
377
  }
378
378
  export function createRouteContext(router, parent, outlet, match) {
379
379
  const { base, location, params } = router;
380
- const { pattern, component, load } = match().route;
380
+ const { pattern, component, preload } = match().route;
381
381
  const path = createMemo(() => match().path);
382
382
  component &&
383
383
  component.preload &&
384
384
  component.preload();
385
- inLoadFn = true;
386
- const data = load ? load({ params, location, intent: intent || "initial" }) : undefined;
387
- inLoadFn = false;
385
+ inPreloadFn = true;
386
+ const data = preload ? preload({ params, location, intent: intent || "initial" }) : undefined;
387
+ inPreloadFn = false;
388
388
  const route = {
389
389
  parent,
390
390
  pattern,
package/dist/types.d.ts CHANGED
@@ -56,12 +56,12 @@ export interface RouterIntegration {
56
56
  utils?: Partial<RouterUtils>;
57
57
  }
58
58
  export type Intent = "initial" | "native" | "navigate" | "preload";
59
- export interface RouteLoadFuncArgs {
59
+ export interface RoutePreloadFuncArgs {
60
60
  params: Params;
61
61
  location: Location;
62
62
  intent: Intent;
63
63
  }
64
- export type RouteLoadFunc<T = unknown> = (args: RouteLoadFuncArgs) => T;
64
+ export type RoutePreloadFunc<T = unknown> = (args: RoutePreloadFuncArgs) => T;
65
65
  export interface RouteSectionProps<T = unknown> {
66
66
  params: Params;
67
67
  location: Location;
@@ -71,10 +71,12 @@ export interface RouteSectionProps<T = unknown> {
71
71
  export type RouteDefinition<S extends string | string[] = any, T = unknown> = {
72
72
  path?: S;
73
73
  matchFilters?: MatchFilters<S>;
74
- load?: RouteLoadFunc<T>;
74
+ preload?: RoutePreloadFunc<T>;
75
75
  children?: RouteDefinition | RouteDefinition[];
76
76
  component?: Component<RouteSectionProps<T>>;
77
77
  info?: Record<string, any>;
78
+ /** @deprecated use preload */
79
+ load?: RoutePreloadFunc;
78
80
  };
79
81
  export type MatchFilter = readonly string[] | RegExp | ((s: string) => boolean);
80
82
  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] : [];
@@ -100,7 +102,7 @@ export interface RouteDescription {
100
102
  originalPath: string;
101
103
  pattern: string;
102
104
  component?: Component<RouteSectionProps>;
103
- load?: RouteLoadFunc;
105
+ preload?: RoutePreloadFunc;
104
106
  matcher: (location: string) => PathMatch | null;
105
107
  matchFilters?: MatchFilters;
106
108
  info?: Record<string, any>;
@@ -181,3 +183,15 @@ export interface MaybePreloadableComponent extends Component {
181
183
  export type CacheEntry = [number, any, Intent | undefined, Signal<number> & {
182
184
  count: number;
183
185
  }];
186
+ export type NarrowResponse<T> = T extends CustomResponse<infer U> ? U : Exclude<T, Response>;
187
+ export type RouterResponseInit = Omit<ResponseInit, "body"> & {
188
+ revalidate?: string | string[];
189
+ };
190
+ export type CustomResponse<T> = Omit<Response, "clone"> & {
191
+ customBody: () => T;
192
+ clone(...args: readonly unknown[]): CustomResponse<T>;
193
+ };
194
+ /** @deprecated */
195
+ export type RouteLoadFunc = RoutePreloadFunc;
196
+ /** @deprecated */
197
+ export type RouteLoadFuncArgs = RoutePreloadFuncArgs;
package/package.json CHANGED
@@ -6,7 +6,7 @@
6
6
  "Ryan Turnquist"
7
7
  ],
8
8
  "license": "MIT",
9
- "version": "0.13.6",
9
+ "version": "0.14.0",
10
10
  "homepage": "https://github.com/solidjs/solid-router#readme",
11
11
  "repository": {
12
12
  "type": "git",