@solidjs/router 0.4.3 → 0.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +49 -33
- package/dist/components.d.ts +5 -6
- package/dist/components.jsx +18 -22
- package/dist/index.d.ts +3 -2
- package/dist/index.js +121 -204
- package/dist/index.jsx +2 -1
- package/dist/lifecycle.d.ts +2 -0
- package/dist/lifecycle.js +32 -0
- package/dist/routing.d.ts +3 -2
- package/dist/routing.js +29 -17
- package/dist/types.d.ts +19 -0
- package/dist/utils.d.ts +1 -0
- package/dist/utils.js +5 -5
- package/package.json +15 -14
package/README.md
CHANGED
|
@@ -28,6 +28,7 @@ It supports all of Solid's SSR methods and has Solid's transitions baked in, so
|
|
|
28
28
|
- [useRouteData](#useroutedata)
|
|
29
29
|
- [useMatch](#usematch)
|
|
30
30
|
- [useRoutes](#useroutes)
|
|
31
|
+
- [useBeforeLeave](#usebeforeleave)
|
|
31
32
|
|
|
32
33
|
## Getting Started
|
|
33
34
|
|
|
@@ -98,7 +99,7 @@ export default function App() {
|
|
|
98
99
|
|
|
99
100
|
3. Lazy-load route components
|
|
100
101
|
|
|
101
|
-
This way, the `Users` and `Home` components will only be loaded if you're navigating to `/users` or
|
|
102
|
+
This way, the `Users` and `Home` components will only be loaded if you're navigating to `/users` or `/`, respectively.
|
|
102
103
|
|
|
103
104
|
```jsx
|
|
104
105
|
import { lazy } from "solid-js";
|
|
@@ -120,11 +121,11 @@ export default function App() {
|
|
|
120
121
|
|
|
121
122
|
## Create Links to Your Routes
|
|
122
123
|
|
|
123
|
-
Use the `
|
|
124
|
+
Use the `A` component to create an anchor tag that takes you to a route:
|
|
124
125
|
|
|
125
126
|
```jsx
|
|
126
127
|
import { lazy } from "solid-js";
|
|
127
|
-
import { Routes, Route,
|
|
128
|
+
import { Routes, Route, A } from "@solidjs/router"
|
|
128
129
|
const Users = lazy(() => import("./pages/Users"));
|
|
129
130
|
const Home = lazy(() => import("./pages/Home"));
|
|
130
131
|
|
|
@@ -132,8 +133,8 @@ export default function App() {
|
|
|
132
133
|
return <>
|
|
133
134
|
<h1>My Site with Lots of Pages</h1>
|
|
134
135
|
<nav>
|
|
135
|
-
<
|
|
136
|
-
<
|
|
136
|
+
<A href="/about">About</A>
|
|
137
|
+
<A href="/">Home</A>
|
|
137
138
|
</nav>
|
|
138
139
|
<Routes>
|
|
139
140
|
<Route path="/users" component={Users} />
|
|
@@ -144,33 +145,21 @@ export default function App() {
|
|
|
144
145
|
}
|
|
145
146
|
```
|
|
146
147
|
|
|
147
|
-
|
|
148
|
+
The `<A>` tag also has an `active` class if its href matches the current location, and `inactive` otherwise. **Note:** By default matching includes locations that are descendents (eg. href `/users` matches locations `/users` and `/users/123`), use the boolean `end` prop to prevent matching these. This is particularly useful for links to the root route `/` which would match everything.
|
|
148
149
|
|
|
149
|
-
Both of these components have these props:
|
|
150
150
|
|
|
151
151
|
| prop | type | description |
|
|
152
152
|
|----------|---------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
|
153
153
|
| href | string | The path of the route to navigate to. This will be resolved relative to the route that the link is in, but you can preface it with `/` to refer back to the root. |
|
|
154
154
|
| noScroll | boolean | If true, turn off the default behavior of scrolling to the top of the new page |
|
|
155
155
|
| replace | boolean | If true, don't add a new entry to the browser history. (By default, the new page will be added to the browser history, so pressing the back button will take you to the previous route.) |
|
|
156
|
-
| state | unknown | [Push this value](https://developer.mozilla.org/en-US/docs/Web/API/History/pushState) to the history stack when navigating |
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
`NavLink` additionally has:
|
|
160
|
-
|
|
161
|
-
| prop | type | description |
|
|
162
|
-
|----------|---------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
|
156
|
+
| state | unknown | [Push this value](https://developer.mozilla.org/en-US/docs/Web/API/History/pushState) to the history stack when navigating | |
|
|
163
157
|
| inactiveClass | string | The class to show when the link is inactive (when the current location doesn't match the link) |
|
|
164
158
|
| activeClass | string | The class to show when the link is active |
|
|
165
159
|
| end | boolean | If `true`, only considers the link to be active when the curent location matches the `href` exactly; if `false`, check if the current location _starts with_ `href` |
|
|
166
160
|
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
If you have a same-domain path that you want to link to _without_ going through the router, set `rel="external"` on the link component.
|
|
171
|
-
|
|
172
161
|
### The Navigate Component
|
|
173
|
-
Solid Router provides a `Navigate` component that works similarly to `
|
|
162
|
+
Solid Router provides a `Navigate` component that works similarly to `A`, but it will _immediately_ navigate to the provided path as soon as the component is rendered. It also uses the `href` prop, but you have the additional option of passing a function to `href` that returns a path to navigate to:
|
|
174
163
|
|
|
175
164
|
```jsx
|
|
176
165
|
function getPath ({navigate, location}) {
|
|
@@ -180,9 +169,7 @@ function getPath ({navigate, location}) {
|
|
|
180
169
|
}
|
|
181
170
|
|
|
182
171
|
//Navigating to /redirect will redirect you to the result of getPath
|
|
183
|
-
<Route path="/redirect"
|
|
184
|
-
<Navigate href={getPath}/>
|
|
185
|
-
</Route>
|
|
172
|
+
<Route path="/redirect" element={<Navigate href={getPath}/>}/>
|
|
186
173
|
```
|
|
187
174
|
|
|
188
175
|
## Dynamic Routes
|
|
@@ -198,7 +185,7 @@ const Home = lazy(() => import("./pages/Home"));
|
|
|
198
185
|
|
|
199
186
|
export default function App() {
|
|
200
187
|
return <>
|
|
201
|
-
<h1>My Site with Lots of Pages
|
|
188
|
+
<h1>My Site with Lots of Pages</h1>
|
|
202
189
|
<Routes>
|
|
203
190
|
<Route path="/users" component={Users} />
|
|
204
191
|
<Route path="/users/:id" component={User} />
|
|
@@ -224,7 +211,7 @@ export default function User () {
|
|
|
224
211
|
|
|
225
212
|
const [userData] = createResource(() => params.id, fetchUser);
|
|
226
213
|
|
|
227
|
-
return <
|
|
214
|
+
return <A href={userData.twitter}>{userData.name}</A>
|
|
228
215
|
}
|
|
229
216
|
```
|
|
230
217
|
|
|
@@ -273,9 +260,9 @@ To do this, create a function that fetches and returns the data using `createRes
|
|
|
273
260
|
```js
|
|
274
261
|
import { lazy } from "solid-js";
|
|
275
262
|
import { Route } from "@solidjs/router";
|
|
276
|
-
import { fetchUser } ...
|
|
263
|
+
import { fetchUser } ...
|
|
277
264
|
|
|
278
|
-
const User = lazy(() => import("
|
|
265
|
+
const User = lazy(() => import("./pages/users/[id].js"));
|
|
279
266
|
|
|
280
267
|
//Data function
|
|
281
268
|
function UserData({params, location, navigate, data}) {
|
|
@@ -361,7 +348,7 @@ function PageWrapper () {
|
|
|
361
348
|
return <div>
|
|
362
349
|
<h1> We love our users! </h1>
|
|
363
350
|
<Outlet/>
|
|
364
|
-
<
|
|
351
|
+
<A href="/">Back Home</A>
|
|
365
352
|
</div>
|
|
366
353
|
}
|
|
367
354
|
|
|
@@ -401,7 +388,7 @@ You don't have to use JSX to set up your routes; you can pass an object directly
|
|
|
401
388
|
```jsx
|
|
402
389
|
import { lazy } from "solid-js";
|
|
403
390
|
import { render } from "solid-js/web";
|
|
404
|
-
import { Router, useRoutes,
|
|
391
|
+
import { Router, useRoutes, A } from "@solidjs/router";
|
|
405
392
|
|
|
406
393
|
const routes = [
|
|
407
394
|
{
|
|
@@ -432,12 +419,12 @@ function App() {
|
|
|
432
419
|
return (
|
|
433
420
|
<>
|
|
434
421
|
<h1>Awesome Site</h1>
|
|
435
|
-
<
|
|
422
|
+
<A class="nav" href="/">
|
|
436
423
|
Home
|
|
437
|
-
</
|
|
438
|
-
<
|
|
424
|
+
</A>
|
|
425
|
+
<A class="nav" href="/users">
|
|
439
426
|
Users
|
|
440
|
-
</
|
|
427
|
+
</A>
|
|
441
428
|
<Routes />
|
|
442
429
|
</>
|
|
443
430
|
);
|
|
@@ -552,3 +539,32 @@ return <div classList={{ active: Boolean(match()) }} />;
|
|
|
552
539
|
### useRoutes
|
|
553
540
|
|
|
554
541
|
Used to define routes via a config object instead of JSX. See [Config Based Routing](#config-based-routing).
|
|
542
|
+
|
|
543
|
+
### useBeforeLeave
|
|
544
|
+
|
|
545
|
+
`useBeforeLeave` takes a function that will be called prior to leaving a route. The function will be called with:
|
|
546
|
+
|
|
547
|
+
- from (_Location_): current location (before change).
|
|
548
|
+
- to (_string | number_}: path passed to `navigate`.
|
|
549
|
+
- options (_NavigateOptions_}: options passed to `navigate`.
|
|
550
|
+
- preventDefault (_void function_): call to block the route change.
|
|
551
|
+
- defaultPrevented (_readonly boolean_): true if any previously called leave handlers called preventDefault().
|
|
552
|
+
- retry (_void function_, _force?: boolean_ ): call to retry the same navigation, perhaps after confirming with the user. Pass `true` to skip running the leave handlers again (ie force navigate without confirming).
|
|
553
|
+
|
|
554
|
+
Example usage:
|
|
555
|
+
```js
|
|
556
|
+
useBeforeLeave((e: BeforeLeaveEventArgs) => {
|
|
557
|
+
if (form.isDirty && !e.defaultPrevented) {
|
|
558
|
+
// preventDefault to block immediately and prompt user async
|
|
559
|
+
e.preventDefault();
|
|
560
|
+
setTimeout(() => {
|
|
561
|
+
if (window.confirm("Discard unsaved changes - are you sure?")) {
|
|
562
|
+
// user wants to proceed anyway so retry with force=true
|
|
563
|
+
e.retry(true);
|
|
564
|
+
}
|
|
565
|
+
}, 100);
|
|
566
|
+
}
|
|
567
|
+
});
|
|
568
|
+
```
|
|
569
|
+
|
|
570
|
+
|
package/dist/components.d.ts
CHANGED
|
@@ -6,6 +6,7 @@ declare module "solid-js" {
|
|
|
6
6
|
state?: string;
|
|
7
7
|
noScroll?: boolean;
|
|
8
8
|
replace?: boolean;
|
|
9
|
+
link?: boolean;
|
|
9
10
|
}
|
|
10
11
|
}
|
|
11
12
|
}
|
|
@@ -27,7 +28,7 @@ export interface RoutesProps {
|
|
|
27
28
|
children: JSX.Element;
|
|
28
29
|
}
|
|
29
30
|
export declare const Routes: (props: RoutesProps) => JSX.Element;
|
|
30
|
-
export declare const useRoutes: (routes: RouteDefinition | RouteDefinition[], base?: string
|
|
31
|
+
export declare const useRoutes: (routes: RouteDefinition | RouteDefinition[], base?: string) => () => JSX.Element;
|
|
31
32
|
export declare type RouteProps = {
|
|
32
33
|
path: string | string[];
|
|
33
34
|
children?: JSX.Element;
|
|
@@ -42,19 +43,17 @@ export declare type RouteProps = {
|
|
|
42
43
|
});
|
|
43
44
|
export declare const Route: (props: RouteProps) => JSX.Element;
|
|
44
45
|
export declare const Outlet: () => JSX.Element;
|
|
45
|
-
export interface
|
|
46
|
+
export interface AnchorProps extends Omit<JSX.AnchorHTMLAttributes<HTMLAnchorElement>, "state"> {
|
|
46
47
|
href: string;
|
|
47
48
|
replace?: boolean;
|
|
48
49
|
noScroll?: boolean;
|
|
49
50
|
state?: unknown;
|
|
50
|
-
}
|
|
51
|
-
export declare function Link(props: LinkProps): JSX.Element;
|
|
52
|
-
export interface NavLinkProps extends LinkProps {
|
|
53
51
|
inactiveClass?: string;
|
|
54
52
|
activeClass?: string;
|
|
55
53
|
end?: boolean;
|
|
56
54
|
}
|
|
57
|
-
export declare function
|
|
55
|
+
export declare function A(props: AnchorProps): JSX.Element;
|
|
56
|
+
export { A as Link, A as NavLink, AnchorProps as LinkProps, AnchorProps as NavLinkProps };
|
|
58
57
|
export interface NavigateProps {
|
|
59
58
|
href: ((args: {
|
|
60
59
|
navigate: Navigator;
|
package/dist/components.jsx
CHANGED
|
@@ -3,7 +3,7 @@ import { children, createMemo, createRoot, mergeProps, on, Show, splitProps } fr
|
|
|
3
3
|
import { isServer } from "solid-js/web";
|
|
4
4
|
import { pathIntegration, staticIntegration } from "./integration";
|
|
5
5
|
import { createBranches, createRouteContext, createRouterContext, getRouteMatches, RouteContextObj, RouterContextObj, useHref, useLocation, useNavigate, useResolvedPath, useRoute, useRouter } from "./routing";
|
|
6
|
-
import { joinPaths } from "./utils";
|
|
6
|
+
import { joinPaths, normalizePath } from "./utils";
|
|
7
7
|
export const Router = (props) => {
|
|
8
8
|
const { source, url, base, data, out } = props;
|
|
9
9
|
const integration = source || (isServer ? staticIntegration({ value: url || "" }) : pathIntegration());
|
|
@@ -54,7 +54,7 @@ export const Routes = (props) => {
|
|
|
54
54
|
return next;
|
|
55
55
|
}));
|
|
56
56
|
return (<Show when={routeStates() && root}>
|
|
57
|
-
{route => <RouteContextObj.Provider value={route}>{route.outlet()}</RouteContextObj.Provider>}
|
|
57
|
+
{((route) => (<RouteContextObj.Provider value={route}>{route.outlet()}</RouteContextObj.Provider>))}
|
|
58
58
|
</Show>);
|
|
59
59
|
};
|
|
60
60
|
export const useRoutes = (routes, base) => {
|
|
@@ -71,36 +71,32 @@ export const Route = (props) => {
|
|
|
71
71
|
export const Outlet = () => {
|
|
72
72
|
const route = useRoute();
|
|
73
73
|
return (<Show when={route.child}>
|
|
74
|
-
{child => <RouteContextObj.Provider value={child}>{child.outlet()}</RouteContextObj.Provider>}
|
|
74
|
+
{((child) => (<RouteContextObj.Provider value={child}>{child.outlet()}</RouteContextObj.Provider>))}
|
|
75
75
|
</Show>);
|
|
76
76
|
};
|
|
77
|
-
function
|
|
78
|
-
const [, rest] = splitProps(props, ["children", "to", "href", "state"]);
|
|
79
|
-
const href = useHref(() => props.to);
|
|
80
|
-
return (<a {...rest} href={href() || props.href} state={JSON.stringify(props.state)}>
|
|
81
|
-
{props.children}
|
|
82
|
-
</a>);
|
|
83
|
-
}
|
|
84
|
-
export function Link(props) {
|
|
85
|
-
const to = useResolvedPath(() => props.href);
|
|
86
|
-
return <LinkBase {...props} to={to()}/>;
|
|
87
|
-
}
|
|
88
|
-
export function NavLink(props) {
|
|
77
|
+
export function A(props) {
|
|
89
78
|
props = mergeProps({ inactiveClass: "inactive", activeClass: "active" }, props);
|
|
90
|
-
const [, rest] = splitProps(props, ["activeClass", "inactiveClass", "end"]);
|
|
91
|
-
const location = useLocation();
|
|
79
|
+
const [, rest] = splitProps(props, ["href", "state", "class", "activeClass", "inactiveClass", "end"]);
|
|
92
80
|
const to = useResolvedPath(() => props.href);
|
|
81
|
+
const href = useHref(to);
|
|
82
|
+
const location = useLocation();
|
|
93
83
|
const isActive = createMemo(() => {
|
|
94
84
|
const to_ = to();
|
|
95
|
-
if (to_ === undefined)
|
|
85
|
+
if (to_ === undefined)
|
|
96
86
|
return false;
|
|
97
|
-
|
|
98
|
-
const
|
|
99
|
-
const loc = location.pathname.toLowerCase();
|
|
87
|
+
const path = normalizePath(to_.split(/[?#]/, 1)[0]).toLowerCase();
|
|
88
|
+
const loc = normalizePath(location.pathname).toLowerCase();
|
|
100
89
|
return props.end ? path === loc : loc.startsWith(path);
|
|
101
90
|
});
|
|
102
|
-
return (<
|
|
91
|
+
return (<a link {...rest} href={href() || props.href} state={JSON.stringify(props.state)} classList={{
|
|
92
|
+
...(props.class && { [props.class]: true }),
|
|
93
|
+
[props.inactiveClass]: !isActive(),
|
|
94
|
+
[props.activeClass]: isActive(),
|
|
95
|
+
...rest.classList
|
|
96
|
+
}} aria-current={isActive() ? "page" : undefined}/>);
|
|
103
97
|
}
|
|
98
|
+
// deprecated alias exports
|
|
99
|
+
export { A as Link, A as NavLink };
|
|
104
100
|
export function Navigate(props) {
|
|
105
101
|
const navigate = useNavigate();
|
|
106
102
|
const location = useLocation();
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
export * from "./components";
|
|
2
2
|
export * from "./integration";
|
|
3
|
-
export
|
|
3
|
+
export * from "./lifecycle";
|
|
4
|
+
export { useRouteData, useHref, useIsRouting, useLocation, useMatch, useNavigate, useParams, useResolvedPath, useSearchParams, useBeforeLeave, } from "./routing";
|
|
4
5
|
export { mergeSearchString as _mergeSearchString } from "./utils";
|
|
5
|
-
export type { Location, LocationChange, LocationChangeSignal, NavigateOptions, Navigator, OutputMatch, Params, RouteDataFunc, RouteDataFuncArgs, RouteDefinition, RouterIntegration, RouterOutput, RouterUtils, SetParams } from "./types";
|
|
6
|
+
export type { Location, LocationChange, LocationChangeSignal, NavigateOptions, Navigator, OutputMatch, Params, RouteDataFunc, RouteDataFuncArgs, RouteDefinition, RouterIntegration, RouterOutput, RouterUtils, SetParams, BeforeLeaveEventArgs } from "./types";
|