@solidjs/router 0.15.0 → 0.15.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.
- package/README.md +8 -7
- package/dist/data/action.d.ts +1 -1
- package/dist/data/action.js +1 -1
- package/dist/data/query.d.ts +3 -0
- package/dist/data/query.js +3 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +158 -3
- package/dist/routing.d.ts +143 -1
- package/dist/routing.js +143 -1
- package/package.json +16 -16
package/README.md
CHANGED
|
@@ -818,7 +818,7 @@ if (unauthorized) {
|
|
|
818
818
|
|
|
819
819
|
### useLocation
|
|
820
820
|
|
|
821
|
-
Retrieves reactive `location` object useful for getting things like `pathname
|
|
821
|
+
Retrieves reactive `location` object useful for getting things like `pathname`.
|
|
822
822
|
|
|
823
823
|
```js
|
|
824
824
|
const location = useLocation();
|
|
@@ -880,7 +880,8 @@ return <div classList={{ active: Boolean(match()) }} />;
|
|
|
880
880
|
For example if you stored breadcrumbs on your route definition you could retrieve them like so:
|
|
881
881
|
```js
|
|
882
882
|
const matches = useCurrentMatches();
|
|
883
|
-
|
|
883
|
+
|
|
884
|
+
const breadcrumbs = createMemo(() => matches().map(m => m.route.info.breadcrumb));
|
|
884
885
|
```
|
|
885
886
|
|
|
886
887
|
### usePreloadRoute
|
|
@@ -898,11 +899,11 @@ preload(`/users/settings`, { preloadData: true });
|
|
|
898
899
|
`useBeforeLeave` takes a function that will be called prior to leaving a route. The function will be called with:
|
|
899
900
|
|
|
900
901
|
- from (_Location_): current location (before change).
|
|
901
|
-
- to (_string | number_
|
|
902
|
-
- options (_NavigateOptions_
|
|
903
|
-
- preventDefault (
|
|
904
|
-
- defaultPrevented (_readonly boolean_): true if any previously called leave handlers called preventDefault
|
|
905
|
-
- retry (
|
|
902
|
+
- to (_string | number_): path passed to `navigate`.
|
|
903
|
+
- options (_NavigateOptions_): options passed to `navigate`.
|
|
904
|
+
- preventDefault (_function_): call to block the route change.
|
|
905
|
+
- defaultPrevented (_readonly boolean_): `true` if any previously called leave handlers called `preventDefault`.
|
|
906
|
+
- retry (_function_, _force?: boolean_ ): call to retry the same navigation, perhaps after confirming with the user. Pass `true` to skip running the leave handlers again (i.e. force navigate without confirming).
|
|
906
907
|
|
|
907
908
|
Example usage:
|
|
908
909
|
|
package/dist/data/action.d.ts
CHANGED
|
@@ -13,5 +13,5 @@ export declare function useAction<T extends Array<any>, U, V>(action: Action<T,
|
|
|
13
13
|
export declare function action<T extends Array<any>, U = void>(fn: (...args: T) => Promise<U>, name?: string): Action<T, U>;
|
|
14
14
|
export declare function action<T extends Array<any>, U = void>(fn: (...args: T) => Promise<U>, options?: {
|
|
15
15
|
name?: string;
|
|
16
|
-
onComplete?: (s: Submission<T, U>) =>
|
|
16
|
+
onComplete?: (s: Submission<T, U>) => void;
|
|
17
17
|
}): Action<T, U>;
|
package/dist/data/action.js
CHANGED
|
@@ -47,7 +47,7 @@ export function action(fn, options = {}) {
|
|
|
47
47
|
return async (res) => {
|
|
48
48
|
const result = await handleResponse(res, error, router.navigatorFactory());
|
|
49
49
|
let retry = null;
|
|
50
|
-
|
|
50
|
+
o.onComplete?.({
|
|
51
51
|
...submission,
|
|
52
52
|
result: result?.data,
|
|
53
53
|
error: result?.error,
|
package/dist/data/query.d.ts
CHANGED
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
import type { CacheEntry, NarrowResponse } from "../types.js";
|
|
2
|
+
/**
|
|
3
|
+
* Revalidates the given cache entry/entries.
|
|
4
|
+
*/
|
|
2
5
|
export declare function revalidate(key?: string | string[] | void, force?: boolean): Promise<void>;
|
|
3
6
|
export declare function cacheKeyOp(key: string | string[] | void, fn: (cacheEntry: CacheEntry) => void): void;
|
|
4
7
|
export type CachedFunction<T extends (...args: any) => any> = T extends (...args: infer A) => infer R ? ([] extends {
|
package/dist/data/query.js
CHANGED
|
@@ -24,6 +24,9 @@ function getCache() {
|
|
|
24
24
|
throw new Error("Cannot find cache context");
|
|
25
25
|
return (req.router || (req.router = {})).cache || (req.router.cache = new Map());
|
|
26
26
|
}
|
|
27
|
+
/**
|
|
28
|
+
* Revalidates the given cache entry/entries.
|
|
29
|
+
*/
|
|
27
30
|
export function revalidate(key, force = true) {
|
|
28
31
|
return startTransition(() => {
|
|
29
32
|
const now = Date.now();
|
package/dist/index.d.ts
CHANGED
|
@@ -4,4 +4,4 @@ export * from "./lifecycle.js";
|
|
|
4
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, RoutePreloadFunc, RoutePreloadFuncArgs, RouteDefinition, RouteDescription, RouteMatch, RouterIntegration, RouterUtils, SetParams, BeforeLeaveEventArgs, RouteLoadFunc, RouteLoadFuncArgs, RouterResponseInit, CustomResponse } from "./types.js";
|
|
7
|
+
export type { Location, LocationChange, MatchFilter, MatchFilters, NavigateOptions, Navigator, OutputMatch, Params, PathMatch, RouteSectionProps, RoutePreloadFunc, RoutePreloadFuncArgs, RouteDefinition, RouteDescription, RouteMatch, RouterIntegration, RouterUtils, SetParams, Submission, BeforeLeaveEventArgs, RouteLoadFunc, RouteLoadFuncArgs, RouterResponseInit, CustomResponse } from "./types.js";
|
package/dist/index.js
CHANGED
|
@@ -251,13 +251,84 @@ const useHref = to => {
|
|
|
251
251
|
return to_ !== undefined ? router.renderPath(to_) : to_;
|
|
252
252
|
});
|
|
253
253
|
};
|
|
254
|
+
|
|
255
|
+
/**
|
|
256
|
+
* Retrieves method to do navigation. The method accepts a path to navigate to and an optional object with the following options:
|
|
257
|
+
*
|
|
258
|
+
* - resolve (*boolean*, default `true`): resolve the path against the current route
|
|
259
|
+
* - replace (*boolean*, default `false`): replace the history entry
|
|
260
|
+
* - scroll (*boolean*, default `true`): scroll to top after navigation
|
|
261
|
+
* - state (*any*, default `undefined`): pass custom state to `location.state`
|
|
262
|
+
*
|
|
263
|
+
* **Note**: The state is serialized using the structured clone algorithm which does not support all object types.
|
|
264
|
+
*
|
|
265
|
+
* @example
|
|
266
|
+
* ```js
|
|
267
|
+
* const navigate = useNavigate();
|
|
268
|
+
*
|
|
269
|
+
* if (unauthorized) {
|
|
270
|
+
* navigate("/login", { replace: true });
|
|
271
|
+
* }
|
|
272
|
+
* ```
|
|
273
|
+
*/
|
|
254
274
|
const useNavigate = () => useRouter().navigatorFactory();
|
|
275
|
+
|
|
276
|
+
/**
|
|
277
|
+
* Retrieves reactive `location` object useful for getting things like `pathname`.
|
|
278
|
+
*
|
|
279
|
+
* @example
|
|
280
|
+
* ```js
|
|
281
|
+
* const location = useLocation();
|
|
282
|
+
*
|
|
283
|
+
* const pathname = createMemo(() => parsePath(location.pathname));
|
|
284
|
+
* ```
|
|
285
|
+
*/
|
|
255
286
|
const useLocation = () => useRouter().location;
|
|
287
|
+
|
|
288
|
+
/**
|
|
289
|
+
* Retrieves signal that indicates whether the route is currently in a *Transition*.
|
|
290
|
+
* Useful for showing stale/pending state when the route resolution is *Suspended* during concurrent rendering.
|
|
291
|
+
*
|
|
292
|
+
* @example
|
|
293
|
+
* ```js
|
|
294
|
+
* const isRouting = useIsRouting();
|
|
295
|
+
*
|
|
296
|
+
* return (
|
|
297
|
+
* <div classList={{ "grey-out": isRouting() }}>
|
|
298
|
+
* <MyAwesomeContent />
|
|
299
|
+
* </div>
|
|
300
|
+
* );
|
|
301
|
+
* ```
|
|
302
|
+
*/
|
|
256
303
|
const useIsRouting = () => useRouter().isRouting;
|
|
304
|
+
|
|
305
|
+
/**
|
|
306
|
+
* usePreloadRoute returns a function that can be used to preload a route manual.
|
|
307
|
+
* This is what happens automatically with link hovering and similar focus based behavior, but it is available here as an API.
|
|
308
|
+
*
|
|
309
|
+
* @example
|
|
310
|
+
* ```js
|
|
311
|
+
* const preload = usePreloadRoute();
|
|
312
|
+
*
|
|
313
|
+
* preload(`/users/settings`, { preloadData: true });
|
|
314
|
+
* ```
|
|
315
|
+
*/
|
|
257
316
|
const usePreloadRoute = () => {
|
|
258
317
|
const pre = useRouter().preloadRoute;
|
|
259
318
|
return (url, options = {}) => pre(url instanceof URL ? url : new URL(url, mockBase), options.preloadData);
|
|
260
319
|
};
|
|
320
|
+
|
|
321
|
+
/**
|
|
322
|
+
* `useMatch` takes an accessor that returns the path and creates a `Memo` that returns match information if the current path matches the provided path.
|
|
323
|
+
* Useful for determining if a given path matches the current route.
|
|
324
|
+
*
|
|
325
|
+
* @example
|
|
326
|
+
* ```js
|
|
327
|
+
* const match = useMatch(() => props.href);
|
|
328
|
+
*
|
|
329
|
+
* return <div classList={{ active: Boolean(match()) }} />;
|
|
330
|
+
* ```
|
|
331
|
+
*/
|
|
261
332
|
const useMatch = (path, matchFilters) => {
|
|
262
333
|
const location = useLocation();
|
|
263
334
|
const matchers = createMemo(() => expandOptionals(path()).map(path => createMatcher(path, undefined, matchFilters)));
|
|
@@ -268,8 +339,60 @@ const useMatch = (path, matchFilters) => {
|
|
|
268
339
|
}
|
|
269
340
|
});
|
|
270
341
|
};
|
|
342
|
+
|
|
343
|
+
/**
|
|
344
|
+
* `useCurrentMatches` returns all the matches for the current matched route.
|
|
345
|
+
* Useful for getting all the route information.
|
|
346
|
+
*
|
|
347
|
+
* @example
|
|
348
|
+
* ```js
|
|
349
|
+
* const matches = useCurrentMatches();
|
|
350
|
+
*
|
|
351
|
+
* const breadcrumbs = createMemo(() => matches().map(m => m.route.info.breadcrumb))
|
|
352
|
+
* ```
|
|
353
|
+
*/
|
|
271
354
|
const useCurrentMatches = () => useRouter().matches;
|
|
355
|
+
|
|
356
|
+
/**
|
|
357
|
+
* Retrieves a reactive, store-like object containing the current route path parameters as defined in the Route.
|
|
358
|
+
*
|
|
359
|
+
* @example
|
|
360
|
+
* ```js
|
|
361
|
+
* const params = useParams();
|
|
362
|
+
*
|
|
363
|
+
* // fetch user based on the id path parameter
|
|
364
|
+
* const [user] = createResource(() => params.id, fetchUser);
|
|
365
|
+
* ```
|
|
366
|
+
*/
|
|
272
367
|
const useParams = () => useRouter().params;
|
|
368
|
+
|
|
369
|
+
/**
|
|
370
|
+
* Retrieves a tuple containing a reactive object to read the current location's query parameters and a method to update them.
|
|
371
|
+
* The object is a proxy so you must access properties to subscribe to reactive updates.
|
|
372
|
+
* **Note** that values will be strings and property names will retain their casing.
|
|
373
|
+
*
|
|
374
|
+
* The setter method accepts an object whose entries will be merged into the current query string.
|
|
375
|
+
* Values `''`, `undefined` and `null` will remove the key from the resulting query string.
|
|
376
|
+
* Updates will behave just like a navigation and the setter accepts the same optional second parameter as `navigate` and auto-scrolling is disabled by default.
|
|
377
|
+
*
|
|
378
|
+
* @examples
|
|
379
|
+
* ```js
|
|
380
|
+
* const [searchParams, setSearchParams] = useSearchParams();
|
|
381
|
+
*
|
|
382
|
+
* return (
|
|
383
|
+
* <div>
|
|
384
|
+
* <span>Page: {searchParams.page}</span>
|
|
385
|
+
* <button
|
|
386
|
+
* onClick={() =>
|
|
387
|
+
* setSearchParams({ page: (parseInt(searchParams.page) || 0) + 1 })
|
|
388
|
+
* }
|
|
389
|
+
* >
|
|
390
|
+
* Next Page
|
|
391
|
+
* </button>
|
|
392
|
+
* </div>
|
|
393
|
+
* );
|
|
394
|
+
* ```
|
|
395
|
+
*/
|
|
273
396
|
const useSearchParams = () => {
|
|
274
397
|
const location = useLocation();
|
|
275
398
|
const navigate = useNavigate();
|
|
@@ -283,6 +406,34 @@ const useSearchParams = () => {
|
|
|
283
406
|
};
|
|
284
407
|
return [location.query, setSearchParams];
|
|
285
408
|
};
|
|
409
|
+
|
|
410
|
+
/**
|
|
411
|
+
* useBeforeLeave takes a function that will be called prior to leaving a route.
|
|
412
|
+
* The function will be called with:
|
|
413
|
+
*
|
|
414
|
+
* - from (*Location*): current location (before change).
|
|
415
|
+
* - to (*string | number*): path passed to `navigate`.
|
|
416
|
+
* - options (*NavigateOptions*): options passed to navigate.
|
|
417
|
+
* - preventDefault (*function*): call to block the route change.
|
|
418
|
+
* - defaultPrevented (*readonly boolean*): `true` if any previously called leave handlers called `preventDefault`.
|
|
419
|
+
* - retry (*function*, force?: boolean ): call to retry the same navigation, perhaps after confirming with the user. Pass `true` to skip running the leave handlers again (i.e. force navigate without confirming).
|
|
420
|
+
*
|
|
421
|
+
* @example
|
|
422
|
+
* ```js
|
|
423
|
+
* useBeforeLeave((e: BeforeLeaveEventArgs) => {
|
|
424
|
+
* if (form.isDirty && !e.defaultPrevented) {
|
|
425
|
+
* // preventDefault to block immediately and prompt user async
|
|
426
|
+
* e.preventDefault();
|
|
427
|
+
* setTimeout(() => {
|
|
428
|
+
* if (window.confirm("Discard unsaved changes - are you sure?")) {
|
|
429
|
+
* // user wants to proceed anyway so retry with force=true
|
|
430
|
+
* e.retry(true);
|
|
431
|
+
* }
|
|
432
|
+
* }, 100);
|
|
433
|
+
* }
|
|
434
|
+
* });
|
|
435
|
+
* ```
|
|
436
|
+
*/
|
|
286
437
|
const useBeforeLeave = listener => {
|
|
287
438
|
const s = useRouter().beforeLeave.subscribe({
|
|
288
439
|
listener,
|
|
@@ -462,7 +613,7 @@ function createRouterContext(integration, branches, getContext, options = {}) {
|
|
|
462
613
|
setReference(lastTransitionTarget.value);
|
|
463
614
|
setState(lastTransitionTarget.state);
|
|
464
615
|
resetErrorBoundaries();
|
|
465
|
-
if (!isServer) submissions[1](
|
|
616
|
+
if (!isServer) submissions[1](subs => subs.filter(s => s.pending));
|
|
466
617
|
}).finally(() => {
|
|
467
618
|
if (lastTransitionTarget !== newTarget) return;
|
|
468
619
|
|
|
@@ -832,7 +983,7 @@ function dataOnly(event, routerState, branches) {
|
|
|
832
983
|
}
|
|
833
984
|
|
|
834
985
|
function intercept([value, setValue], get, set) {
|
|
835
|
-
return [
|
|
986
|
+
return [value, set ? v => setValue(set(v)) : setValue];
|
|
836
987
|
}
|
|
837
988
|
function createRouter(config) {
|
|
838
989
|
let ignore = false;
|
|
@@ -906,6 +1057,10 @@ function getCache() {
|
|
|
906
1057
|
if (!req) throw new Error("Cannot find cache context");
|
|
907
1058
|
return (req.router || (req.router = {})).cache || (req.router.cache = new Map());
|
|
908
1059
|
}
|
|
1060
|
+
|
|
1061
|
+
/**
|
|
1062
|
+
* Revalidates the given cache entry/entries.
|
|
1063
|
+
*/
|
|
909
1064
|
function revalidate(key, force = true) {
|
|
910
1065
|
return startTransition(() => {
|
|
911
1066
|
const now = Date.now();
|
|
@@ -1118,7 +1273,7 @@ function action(fn, options = {}) {
|
|
|
1118
1273
|
return async res => {
|
|
1119
1274
|
const result = await handleResponse(res, error, router.navigatorFactory());
|
|
1120
1275
|
let retry = null;
|
|
1121
|
-
|
|
1276
|
+
o.onComplete?.({
|
|
1122
1277
|
...submission,
|
|
1123
1278
|
result: result?.data,
|
|
1124
1279
|
error: result?.error,
|
package/dist/routing.d.ts
CHANGED
|
@@ -6,16 +6,158 @@ export declare const useRouter: () => RouterContext;
|
|
|
6
6
|
export declare const useRoute: () => RouteContext;
|
|
7
7
|
export declare const useResolvedPath: (path: () => string) => Accessor<string | undefined>;
|
|
8
8
|
export declare const useHref: (to: () => string | undefined) => Accessor<string | undefined>;
|
|
9
|
+
/**
|
|
10
|
+
* Retrieves method to do navigation. The method accepts a path to navigate to and an optional object with the following options:
|
|
11
|
+
*
|
|
12
|
+
* - resolve (*boolean*, default `true`): resolve the path against the current route
|
|
13
|
+
* - replace (*boolean*, default `false`): replace the history entry
|
|
14
|
+
* - scroll (*boolean*, default `true`): scroll to top after navigation
|
|
15
|
+
* - state (*any*, default `undefined`): pass custom state to `location.state`
|
|
16
|
+
*
|
|
17
|
+
* **Note**: The state is serialized using the structured clone algorithm which does not support all object types.
|
|
18
|
+
*
|
|
19
|
+
* @example
|
|
20
|
+
* ```js
|
|
21
|
+
* const navigate = useNavigate();
|
|
22
|
+
*
|
|
23
|
+
* if (unauthorized) {
|
|
24
|
+
* navigate("/login", { replace: true });
|
|
25
|
+
* }
|
|
26
|
+
* ```
|
|
27
|
+
*/
|
|
9
28
|
export declare const useNavigate: () => Navigator;
|
|
29
|
+
/**
|
|
30
|
+
* Retrieves reactive `location` object useful for getting things like `pathname`.
|
|
31
|
+
*
|
|
32
|
+
* @example
|
|
33
|
+
* ```js
|
|
34
|
+
* const location = useLocation();
|
|
35
|
+
*
|
|
36
|
+
* const pathname = createMemo(() => parsePath(location.pathname));
|
|
37
|
+
* ```
|
|
38
|
+
*/
|
|
10
39
|
export declare const useLocation: <S = unknown>() => Location<S>;
|
|
40
|
+
/**
|
|
41
|
+
* Retrieves signal that indicates whether the route is currently in a *Transition*.
|
|
42
|
+
* Useful for showing stale/pending state when the route resolution is *Suspended* during concurrent rendering.
|
|
43
|
+
*
|
|
44
|
+
* @example
|
|
45
|
+
* ```js
|
|
46
|
+
* const isRouting = useIsRouting();
|
|
47
|
+
*
|
|
48
|
+
* return (
|
|
49
|
+
* <div classList={{ "grey-out": isRouting() }}>
|
|
50
|
+
* <MyAwesomeContent />
|
|
51
|
+
* </div>
|
|
52
|
+
* );
|
|
53
|
+
* ```
|
|
54
|
+
*/
|
|
11
55
|
export declare const useIsRouting: () => () => boolean;
|
|
56
|
+
/**
|
|
57
|
+
* usePreloadRoute returns a function that can be used to preload a route manual.
|
|
58
|
+
* This is what happens automatically with link hovering and similar focus based behavior, but it is available here as an API.
|
|
59
|
+
*
|
|
60
|
+
* @example
|
|
61
|
+
* ```js
|
|
62
|
+
* const preload = usePreloadRoute();
|
|
63
|
+
*
|
|
64
|
+
* preload(`/users/settings`, { preloadData: true });
|
|
65
|
+
* ```
|
|
66
|
+
*/
|
|
12
67
|
export declare const usePreloadRoute: () => (url: string | URL, options?: {
|
|
13
68
|
preloadData?: boolean;
|
|
14
69
|
}) => void;
|
|
15
|
-
|
|
70
|
+
/**
|
|
71
|
+
* `useMatch` takes an accessor that returns the path and creates a `Memo` that returns match information if the current path matches the provided path.
|
|
72
|
+
* Useful for determining if a given path matches the current route.
|
|
73
|
+
*
|
|
74
|
+
* @example
|
|
75
|
+
* ```js
|
|
76
|
+
* const match = useMatch(() => props.href);
|
|
77
|
+
*
|
|
78
|
+
* return <div classList={{ active: Boolean(match()) }} />;
|
|
79
|
+
* ```
|
|
80
|
+
*/
|
|
81
|
+
export declare const useMatch: <S extends string>(path: () => S, matchFilters?: MatchFilters<S>) => Accessor<import("./types.js").PathMatch | undefined>;
|
|
82
|
+
/**
|
|
83
|
+
* `useCurrentMatches` returns all the matches for the current matched route.
|
|
84
|
+
* Useful for getting all the route information.
|
|
85
|
+
*
|
|
86
|
+
* @example
|
|
87
|
+
* ```js
|
|
88
|
+
* const matches = useCurrentMatches();
|
|
89
|
+
*
|
|
90
|
+
* const breadcrumbs = createMemo(() => matches().map(m => m.route.info.breadcrumb))
|
|
91
|
+
* ```
|
|
92
|
+
*/
|
|
16
93
|
export declare const useCurrentMatches: () => () => RouteMatch[];
|
|
94
|
+
/**
|
|
95
|
+
* Retrieves a reactive, store-like object containing the current route path parameters as defined in the Route.
|
|
96
|
+
*
|
|
97
|
+
* @example
|
|
98
|
+
* ```js
|
|
99
|
+
* const params = useParams();
|
|
100
|
+
*
|
|
101
|
+
* // fetch user based on the id path parameter
|
|
102
|
+
* const [user] = createResource(() => params.id, fetchUser);
|
|
103
|
+
* ```
|
|
104
|
+
*/
|
|
17
105
|
export declare const useParams: <T extends Params>() => T;
|
|
106
|
+
/**
|
|
107
|
+
* Retrieves a tuple containing a reactive object to read the current location's query parameters and a method to update them.
|
|
108
|
+
* The object is a proxy so you must access properties to subscribe to reactive updates.
|
|
109
|
+
* **Note** that values will be strings and property names will retain their casing.
|
|
110
|
+
*
|
|
111
|
+
* The setter method accepts an object whose entries will be merged into the current query string.
|
|
112
|
+
* Values `''`, `undefined` and `null` will remove the key from the resulting query string.
|
|
113
|
+
* Updates will behave just like a navigation and the setter accepts the same optional second parameter as `navigate` and auto-scrolling is disabled by default.
|
|
114
|
+
*
|
|
115
|
+
* @examples
|
|
116
|
+
* ```js
|
|
117
|
+
* const [searchParams, setSearchParams] = useSearchParams();
|
|
118
|
+
*
|
|
119
|
+
* return (
|
|
120
|
+
* <div>
|
|
121
|
+
* <span>Page: {searchParams.page}</span>
|
|
122
|
+
* <button
|
|
123
|
+
* onClick={() =>
|
|
124
|
+
* setSearchParams({ page: (parseInt(searchParams.page) || 0) + 1 })
|
|
125
|
+
* }
|
|
126
|
+
* >
|
|
127
|
+
* Next Page
|
|
128
|
+
* </button>
|
|
129
|
+
* </div>
|
|
130
|
+
* );
|
|
131
|
+
* ```
|
|
132
|
+
*/
|
|
18
133
|
export declare const useSearchParams: <T extends SearchParams>() => [Partial<T>, (params: SetSearchParams, options?: Partial<NavigateOptions>) => void];
|
|
134
|
+
/**
|
|
135
|
+
* useBeforeLeave takes a function that will be called prior to leaving a route.
|
|
136
|
+
* The function will be called with:
|
|
137
|
+
*
|
|
138
|
+
* - from (*Location*): current location (before change).
|
|
139
|
+
* - to (*string | number*): path passed to `navigate`.
|
|
140
|
+
* - options (*NavigateOptions*): options passed to navigate.
|
|
141
|
+
* - preventDefault (*function*): call to block the route change.
|
|
142
|
+
* - defaultPrevented (*readonly boolean*): `true` if any previously called leave handlers called `preventDefault`.
|
|
143
|
+
* - retry (*function*, force?: boolean ): call to retry the same navigation, perhaps after confirming with the user. Pass `true` to skip running the leave handlers again (i.e. force navigate without confirming).
|
|
144
|
+
*
|
|
145
|
+
* @example
|
|
146
|
+
* ```js
|
|
147
|
+
* useBeforeLeave((e: BeforeLeaveEventArgs) => {
|
|
148
|
+
* if (form.isDirty && !e.defaultPrevented) {
|
|
149
|
+
* // preventDefault to block immediately and prompt user async
|
|
150
|
+
* e.preventDefault();
|
|
151
|
+
* setTimeout(() => {
|
|
152
|
+
* if (window.confirm("Discard unsaved changes - are you sure?")) {
|
|
153
|
+
* // user wants to proceed anyway so retry with force=true
|
|
154
|
+
* e.retry(true);
|
|
155
|
+
* }
|
|
156
|
+
* }, 100);
|
|
157
|
+
* }
|
|
158
|
+
* });
|
|
159
|
+
* ```
|
|
160
|
+
*/
|
|
19
161
|
export declare const useBeforeLeave: (listener: (e: BeforeLeaveEventArgs) => void) => void;
|
|
20
162
|
export declare function createRoutes(routeDef: RouteDefinition, base?: string): RouteDescription[];
|
|
21
163
|
export declare function createBranch(routes: RouteDescription[], index?: number): Branch;
|
package/dist/routing.js
CHANGED
|
@@ -20,13 +20,79 @@ export const useHref = (to) => {
|
|
|
20
20
|
return to_ !== undefined ? router.renderPath(to_) : to_;
|
|
21
21
|
});
|
|
22
22
|
};
|
|
23
|
+
/**
|
|
24
|
+
* Retrieves method to do navigation. The method accepts a path to navigate to and an optional object with the following options:
|
|
25
|
+
*
|
|
26
|
+
* - resolve (*boolean*, default `true`): resolve the path against the current route
|
|
27
|
+
* - replace (*boolean*, default `false`): replace the history entry
|
|
28
|
+
* - scroll (*boolean*, default `true`): scroll to top after navigation
|
|
29
|
+
* - state (*any*, default `undefined`): pass custom state to `location.state`
|
|
30
|
+
*
|
|
31
|
+
* **Note**: The state is serialized using the structured clone algorithm which does not support all object types.
|
|
32
|
+
*
|
|
33
|
+
* @example
|
|
34
|
+
* ```js
|
|
35
|
+
* const navigate = useNavigate();
|
|
36
|
+
*
|
|
37
|
+
* if (unauthorized) {
|
|
38
|
+
* navigate("/login", { replace: true });
|
|
39
|
+
* }
|
|
40
|
+
* ```
|
|
41
|
+
*/
|
|
23
42
|
export const useNavigate = () => useRouter().navigatorFactory();
|
|
43
|
+
/**
|
|
44
|
+
* Retrieves reactive `location` object useful for getting things like `pathname`.
|
|
45
|
+
*
|
|
46
|
+
* @example
|
|
47
|
+
* ```js
|
|
48
|
+
* const location = useLocation();
|
|
49
|
+
*
|
|
50
|
+
* const pathname = createMemo(() => parsePath(location.pathname));
|
|
51
|
+
* ```
|
|
52
|
+
*/
|
|
24
53
|
export const useLocation = () => useRouter().location;
|
|
54
|
+
/**
|
|
55
|
+
* Retrieves signal that indicates whether the route is currently in a *Transition*.
|
|
56
|
+
* Useful for showing stale/pending state when the route resolution is *Suspended* during concurrent rendering.
|
|
57
|
+
*
|
|
58
|
+
* @example
|
|
59
|
+
* ```js
|
|
60
|
+
* const isRouting = useIsRouting();
|
|
61
|
+
*
|
|
62
|
+
* return (
|
|
63
|
+
* <div classList={{ "grey-out": isRouting() }}>
|
|
64
|
+
* <MyAwesomeContent />
|
|
65
|
+
* </div>
|
|
66
|
+
* );
|
|
67
|
+
* ```
|
|
68
|
+
*/
|
|
25
69
|
export const useIsRouting = () => useRouter().isRouting;
|
|
70
|
+
/**
|
|
71
|
+
* usePreloadRoute returns a function that can be used to preload a route manual.
|
|
72
|
+
* This is what happens automatically with link hovering and similar focus based behavior, but it is available here as an API.
|
|
73
|
+
*
|
|
74
|
+
* @example
|
|
75
|
+
* ```js
|
|
76
|
+
* const preload = usePreloadRoute();
|
|
77
|
+
*
|
|
78
|
+
* preload(`/users/settings`, { preloadData: true });
|
|
79
|
+
* ```
|
|
80
|
+
*/
|
|
26
81
|
export const usePreloadRoute = () => {
|
|
27
82
|
const pre = useRouter().preloadRoute;
|
|
28
83
|
return (url, options = {}) => pre(url instanceof URL ? url : new URL(url, mockBase), options.preloadData);
|
|
29
84
|
};
|
|
85
|
+
/**
|
|
86
|
+
* `useMatch` takes an accessor that returns the path and creates a `Memo` that returns match information if the current path matches the provided path.
|
|
87
|
+
* Useful for determining if a given path matches the current route.
|
|
88
|
+
*
|
|
89
|
+
* @example
|
|
90
|
+
* ```js
|
|
91
|
+
* const match = useMatch(() => props.href);
|
|
92
|
+
*
|
|
93
|
+
* return <div classList={{ active: Boolean(match()) }} />;
|
|
94
|
+
* ```
|
|
95
|
+
*/
|
|
30
96
|
export const useMatch = (path, matchFilters) => {
|
|
31
97
|
const location = useLocation();
|
|
32
98
|
const matchers = createMemo(() => expandOptionals(path()).map(path => createMatcher(path, undefined, matchFilters)));
|
|
@@ -38,8 +104,57 @@ export const useMatch = (path, matchFilters) => {
|
|
|
38
104
|
}
|
|
39
105
|
});
|
|
40
106
|
};
|
|
107
|
+
/**
|
|
108
|
+
* `useCurrentMatches` returns all the matches for the current matched route.
|
|
109
|
+
* Useful for getting all the route information.
|
|
110
|
+
*
|
|
111
|
+
* @example
|
|
112
|
+
* ```js
|
|
113
|
+
* const matches = useCurrentMatches();
|
|
114
|
+
*
|
|
115
|
+
* const breadcrumbs = createMemo(() => matches().map(m => m.route.info.breadcrumb))
|
|
116
|
+
* ```
|
|
117
|
+
*/
|
|
41
118
|
export const useCurrentMatches = () => useRouter().matches;
|
|
119
|
+
/**
|
|
120
|
+
* Retrieves a reactive, store-like object containing the current route path parameters as defined in the Route.
|
|
121
|
+
*
|
|
122
|
+
* @example
|
|
123
|
+
* ```js
|
|
124
|
+
* const params = useParams();
|
|
125
|
+
*
|
|
126
|
+
* // fetch user based on the id path parameter
|
|
127
|
+
* const [user] = createResource(() => params.id, fetchUser);
|
|
128
|
+
* ```
|
|
129
|
+
*/
|
|
42
130
|
export const useParams = () => useRouter().params;
|
|
131
|
+
/**
|
|
132
|
+
* Retrieves a tuple containing a reactive object to read the current location's query parameters and a method to update them.
|
|
133
|
+
* The object is a proxy so you must access properties to subscribe to reactive updates.
|
|
134
|
+
* **Note** that values will be strings and property names will retain their casing.
|
|
135
|
+
*
|
|
136
|
+
* The setter method accepts an object whose entries will be merged into the current query string.
|
|
137
|
+
* Values `''`, `undefined` and `null` will remove the key from the resulting query string.
|
|
138
|
+
* Updates will behave just like a navigation and the setter accepts the same optional second parameter as `navigate` and auto-scrolling is disabled by default.
|
|
139
|
+
*
|
|
140
|
+
* @examples
|
|
141
|
+
* ```js
|
|
142
|
+
* const [searchParams, setSearchParams] = useSearchParams();
|
|
143
|
+
*
|
|
144
|
+
* return (
|
|
145
|
+
* <div>
|
|
146
|
+
* <span>Page: {searchParams.page}</span>
|
|
147
|
+
* <button
|
|
148
|
+
* onClick={() =>
|
|
149
|
+
* setSearchParams({ page: (parseInt(searchParams.page) || 0) + 1 })
|
|
150
|
+
* }
|
|
151
|
+
* >
|
|
152
|
+
* Next Page
|
|
153
|
+
* </button>
|
|
154
|
+
* </div>
|
|
155
|
+
* );
|
|
156
|
+
* ```
|
|
157
|
+
*/
|
|
43
158
|
export const useSearchParams = () => {
|
|
44
159
|
const location = useLocation();
|
|
45
160
|
const navigate = useNavigate();
|
|
@@ -53,6 +168,33 @@ export const useSearchParams = () => {
|
|
|
53
168
|
};
|
|
54
169
|
return [location.query, setSearchParams];
|
|
55
170
|
};
|
|
171
|
+
/**
|
|
172
|
+
* useBeforeLeave takes a function that will be called prior to leaving a route.
|
|
173
|
+
* The function will be called with:
|
|
174
|
+
*
|
|
175
|
+
* - from (*Location*): current location (before change).
|
|
176
|
+
* - to (*string | number*): path passed to `navigate`.
|
|
177
|
+
* - options (*NavigateOptions*): options passed to navigate.
|
|
178
|
+
* - preventDefault (*function*): call to block the route change.
|
|
179
|
+
* - defaultPrevented (*readonly boolean*): `true` if any previously called leave handlers called `preventDefault`.
|
|
180
|
+
* - retry (*function*, force?: boolean ): call to retry the same navigation, perhaps after confirming with the user. Pass `true` to skip running the leave handlers again (i.e. force navigate without confirming).
|
|
181
|
+
*
|
|
182
|
+
* @example
|
|
183
|
+
* ```js
|
|
184
|
+
* useBeforeLeave((e: BeforeLeaveEventArgs) => {
|
|
185
|
+
* if (form.isDirty && !e.defaultPrevented) {
|
|
186
|
+
* // preventDefault to block immediately and prompt user async
|
|
187
|
+
* e.preventDefault();
|
|
188
|
+
* setTimeout(() => {
|
|
189
|
+
* if (window.confirm("Discard unsaved changes - are you sure?")) {
|
|
190
|
+
* // user wants to proceed anyway so retry with force=true
|
|
191
|
+
* e.retry(true);
|
|
192
|
+
* }
|
|
193
|
+
* }, 100);
|
|
194
|
+
* }
|
|
195
|
+
* });
|
|
196
|
+
* ```
|
|
197
|
+
*/
|
|
56
198
|
export const useBeforeLeave = (listener) => {
|
|
57
199
|
const s = useRouter().beforeLeave.subscribe({
|
|
58
200
|
listener,
|
|
@@ -227,7 +369,7 @@ export function createRouterContext(integration, branches, getContext, options =
|
|
|
227
369
|
setState(lastTransitionTarget.state);
|
|
228
370
|
resetErrorBoundaries();
|
|
229
371
|
if (!isServer)
|
|
230
|
-
submissions[1](
|
|
372
|
+
submissions[1](subs => subs.filter(s => s.pending));
|
|
231
373
|
}).finally(() => {
|
|
232
374
|
if (lastTransitionTarget !== newTarget)
|
|
233
375
|
return;
|
package/package.json
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
"Ryan Turnquist"
|
|
7
7
|
],
|
|
8
8
|
"license": "MIT",
|
|
9
|
-
"version": "0.15.
|
|
9
|
+
"version": "0.15.2",
|
|
10
10
|
"homepage": "https://github.com/solidjs/solid-router#readme",
|
|
11
11
|
"repository": {
|
|
12
12
|
"type": "git",
|
|
@@ -29,23 +29,23 @@
|
|
|
29
29
|
],
|
|
30
30
|
"sideEffects": false,
|
|
31
31
|
"devDependencies": {
|
|
32
|
-
"@babel/core": "^7.
|
|
33
|
-
"@babel/preset-typescript": "^7.
|
|
34
|
-
"@changesets/cli": "^2.27.
|
|
32
|
+
"@babel/core": "^7.26.0",
|
|
33
|
+
"@babel/preset-typescript": "^7.26.0",
|
|
34
|
+
"@changesets/cli": "^2.27.10",
|
|
35
35
|
"@rollup/plugin-babel": "6.0.4",
|
|
36
|
-
"@rollup/plugin-node-resolve": "15.
|
|
36
|
+
"@rollup/plugin-node-resolve": "15.3.0",
|
|
37
37
|
"@rollup/plugin-terser": "0.4.4",
|
|
38
|
-
"@types/jest": "^29.5.
|
|
39
|
-
"@types/node": "^
|
|
40
|
-
"babel-preset-solid": "^1.9.
|
|
41
|
-
"jsdom": "^
|
|
42
|
-
"prettier": "^
|
|
43
|
-
"rollup": "^4.
|
|
44
|
-
"solid-js": "^1.9.
|
|
45
|
-
"typescript": "^5.
|
|
46
|
-
"vite": "^
|
|
47
|
-
"vite-plugin-solid": "^2.
|
|
48
|
-
"vitest": "^2.1.
|
|
38
|
+
"@types/jest": "^29.5.14",
|
|
39
|
+
"@types/node": "^22.10.0",
|
|
40
|
+
"babel-preset-solid": "^1.9.3",
|
|
41
|
+
"jsdom": "^25.0.1",
|
|
42
|
+
"prettier": "^3.4.1",
|
|
43
|
+
"rollup": "^4.27.4",
|
|
44
|
+
"solid-js": "^1.9.3",
|
|
45
|
+
"typescript": "^5.7.2",
|
|
46
|
+
"vite": "^6.0.0",
|
|
47
|
+
"vite-plugin-solid": "^2.11.0",
|
|
48
|
+
"vitest": "^2.1.6"
|
|
49
49
|
},
|
|
50
50
|
"peerDependencies": {
|
|
51
51
|
"solid-js": "^1.8.6"
|