@solidjs/router 0.5.1 → 0.7.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 +90 -54
- package/dist/components.d.ts +6 -5
- package/dist/components.jsx +18 -3
- package/dist/index.js +52 -22
- package/dist/routing.d.ts +4 -4
- package/dist/routing.js +26 -14
- package/dist/types.d.ts +14 -7
- package/dist/utils.d.ts +2 -3
- package/dist/utils.js +32 -8
- package/package.json +18 -18
package/README.md
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
|
|
7
7
|
A router lets you change your view based on the URL in the browser. This allows your "single-page" application to simulate a traditional multipage site. To use Solid Router, you specify components called Routes that depend on the value of the URL (the "path"), and the router handles the mechanism of swapping them in and out.
|
|
8
8
|
|
|
9
|
-
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.
|
|
9
|
+
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.
|
|
10
10
|
|
|
11
11
|
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 data function that loads parallel to the routes ([render-as-you-fetch](https://epicreact.dev/render-as-you-fetch/)).
|
|
12
12
|
|
|
@@ -16,8 +16,8 @@ It supports all of Solid's SSR methods and has Solid's transitions baked in, so
|
|
|
16
16
|
- [Create Links to Your Routes](#create-links-to-your-routes)
|
|
17
17
|
- [Dynamic Routes](#dynamic-routes)
|
|
18
18
|
- [Data Functions](#data-functions)
|
|
19
|
-
- [Nested Routes](#nested-routes)
|
|
20
|
-
- [Hash Mode Router](#hash-mode-router)
|
|
19
|
+
- [Nested Routes](#nested-routes)
|
|
20
|
+
- [Hash Mode Router](#hash-mode-router)
|
|
21
21
|
- [Config Based Routing](#config-based-routing)
|
|
22
22
|
- [Router Primitives](#router-primitives)
|
|
23
23
|
- [useParams](#useparams)
|
|
@@ -63,17 +63,16 @@ Solid Router allows you to configure your routes using JSX:
|
|
|
63
63
|
|
|
64
64
|
1. Use the `Routes` component to specify where the routes should appear in your app.
|
|
65
65
|
|
|
66
|
-
|
|
67
66
|
```jsx
|
|
68
67
|
import { Routes, Route } from "@solidjs/router"
|
|
69
68
|
|
|
70
69
|
export default function App() {
|
|
71
70
|
return <>
|
|
72
|
-
|
|
71
|
+
<h1>My Site with Lots of Pages</h1>
|
|
73
72
|
<Routes>
|
|
74
73
|
|
|
75
74
|
</Routes>
|
|
76
|
-
|
|
75
|
+
</>
|
|
77
76
|
}
|
|
78
77
|
```
|
|
79
78
|
|
|
@@ -87,13 +86,13 @@ import Users from "./pages/Users"
|
|
|
87
86
|
|
|
88
87
|
export default function App() {
|
|
89
88
|
return <>
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
89
|
+
<h1>My Site with Lots of Pages</h1>
|
|
90
|
+
<Routes>
|
|
91
|
+
<Route path="/users" component={Users} />
|
|
92
|
+
<Route path="/" component={Home} />
|
|
93
|
+
<Route path="/about" element={<div>This site was made with Solid</div>} />
|
|
94
|
+
</Routes>
|
|
95
|
+
</>
|
|
97
96
|
}
|
|
98
97
|
```
|
|
99
98
|
|
|
@@ -109,13 +108,13 @@ const Home = lazy(() => import("./pages/Home"));
|
|
|
109
108
|
|
|
110
109
|
export default function App() {
|
|
111
110
|
return <>
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
111
|
+
<h1>My Site with Lots of Pages</h1>
|
|
112
|
+
<Routes>
|
|
113
|
+
<Route path="/users" component={Users} />
|
|
114
|
+
<Route path="/" component={Home} />
|
|
115
|
+
<Route path="/about" element={<div>This site was made with Solid</div>} />
|
|
116
|
+
</Routes>
|
|
117
|
+
</>
|
|
119
118
|
}
|
|
120
119
|
```
|
|
121
120
|
|
|
@@ -131,17 +130,17 @@ const Home = lazy(() => import("./pages/Home"));
|
|
|
131
130
|
|
|
132
131
|
export default function App() {
|
|
133
132
|
return <>
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
133
|
+
<h1>My Site with Lots of Pages</h1>
|
|
134
|
+
<nav>
|
|
135
|
+
<A href="/about">About</A>
|
|
136
|
+
<A href="/">Home</A>
|
|
137
|
+
</nav>
|
|
138
|
+
<Routes>
|
|
139
|
+
<Route path="/users" component={Users} />
|
|
140
|
+
<Route path="/" component={Home} />
|
|
141
|
+
<Route path="/about" element={<div>This site was made with Solid</div>} />
|
|
142
|
+
</Routes>
|
|
143
|
+
</>
|
|
145
144
|
}
|
|
146
145
|
```
|
|
147
146
|
|
|
@@ -163,7 +162,7 @@ Solid Router provides a `Navigate` component that works similarly to `A`, but it
|
|
|
163
162
|
|
|
164
163
|
```jsx
|
|
165
164
|
function getPath ({navigate, location}) {
|
|
166
|
-
//navigate is the result of calling useNavigate(); location is the result of calling useLocation().
|
|
165
|
+
//navigate is the result of calling useNavigate(); location is the result of calling useLocation().
|
|
167
166
|
//You can use those to dynamically determine a path to navigate to
|
|
168
167
|
return "/some-path";
|
|
169
168
|
}
|
|
@@ -174,7 +173,7 @@ function getPath ({navigate, location}) {
|
|
|
174
173
|
|
|
175
174
|
## Dynamic Routes
|
|
176
175
|
|
|
177
|
-
If you don't know the path ahead of time, you might want to treat part of the path as a flexible parameter that is passed on to the component.
|
|
176
|
+
If you don't know the path ahead of time, you might want to treat part of the path as a flexible parameter that is passed on to the component.
|
|
178
177
|
|
|
179
178
|
```jsx
|
|
180
179
|
import { lazy } from "solid-js";
|
|
@@ -185,14 +184,14 @@ const Home = lazy(() => import("./pages/Home"));
|
|
|
185
184
|
|
|
186
185
|
export default function App() {
|
|
187
186
|
return <>
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
187
|
+
<h1>My Site with Lots of Pages</h1>
|
|
188
|
+
<Routes>
|
|
189
|
+
<Route path="/users" component={Users} />
|
|
190
|
+
<Route path="/users/:id" component={User} />
|
|
191
|
+
<Route path="/" component={Home} />
|
|
192
|
+
<Route path="/about" element={<div>This site was made with Solid</div>} />
|
|
193
|
+
</Routes>
|
|
194
|
+
</>
|
|
196
195
|
}
|
|
197
196
|
```
|
|
198
197
|
|
|
@@ -200,6 +199,48 @@ The colon indicates that `id` can be any string, and as long as the URL fits tha
|
|
|
200
199
|
|
|
201
200
|
You can then access that `id` from within a route component with `useParams`:
|
|
202
201
|
|
|
202
|
+
---
|
|
203
|
+
|
|
204
|
+
Each path parameter can be validated using a `MatchFilter`.
|
|
205
|
+
This allows for more complex routing descriptions than just checking the presence of a parameter.
|
|
206
|
+
|
|
207
|
+
```tsx
|
|
208
|
+
import {lazy} from "solid-js";
|
|
209
|
+
import {Routes, Route} from "@solidjs/router"
|
|
210
|
+
import type {SegmentValidators} from "./types";
|
|
211
|
+
|
|
212
|
+
const Users = lazy(() => import("./pages/Users"));
|
|
213
|
+
const User = lazy(() => import("./pages/User"));
|
|
214
|
+
const Home = lazy(() => import("./pages/Home"));
|
|
215
|
+
|
|
216
|
+
const filters: MatchFilters = {
|
|
217
|
+
parent: ['mom', 'dad'], // allow enum values
|
|
218
|
+
id: /^\d+$/, // only allow numbers
|
|
219
|
+
withHtmlExtension: (v: string) => v.length > 5 && v.endsWith('.html') // we want an `*.html` extension
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
export default function App() {
|
|
223
|
+
return <>
|
|
224
|
+
<h1>My Site with Lots of Pages</h1>
|
|
225
|
+
<Routes>
|
|
226
|
+
<Route path="/users/:parent/:id/:withHtmlExtension" component={User} matchFilters={filters}/>
|
|
227
|
+
</Routes>
|
|
228
|
+
</>
|
|
229
|
+
}
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
Here, we have added the `matchFilters` prop. This allows us to validate the `parent`, `id` and `withHtmlExtension` parameters against the filters defined in `filters`.
|
|
233
|
+
If the validation fails, the route will not match.
|
|
234
|
+
|
|
235
|
+
So in this example:
|
|
236
|
+
|
|
237
|
+
- `/users/mom/123/contact.html` would match,
|
|
238
|
+
- `/users/dad/123/about.html` would match,
|
|
239
|
+
- `/users/aunt/123/contact.html` would not match as `:parent` is not 'mom' or 'dad',
|
|
240
|
+
- `/users/mom/me/contact.html` would not match as `:id` is not a number,
|
|
241
|
+
- `/users/dad/123/contact` would not match as `:withHtmlExtension` is missing `.html`.
|
|
242
|
+
|
|
243
|
+
---
|
|
203
244
|
|
|
204
245
|
```jsx
|
|
205
246
|
//async fetching function
|
|
@@ -250,12 +291,10 @@ Routes also support defining multiple paths using an array. This allows a route
|
|
|
250
291
|
<Route path={["login", "register"]} component={Login}/>
|
|
251
292
|
```
|
|
252
293
|
|
|
253
|
-
|
|
254
294
|
## Data Functions
|
|
255
295
|
In the [above example](#dynamic-routes), the User component is lazy-loaded and then the data is fetched. With route data functions, we can instead start fetching the data parallel to loading the route, so we can use the data as soon as possible.
|
|
256
296
|
|
|
257
|
-
To do this, create a function that fetches and returns the data using `createResource`. Then pass that function to the `data` prop of the `Route` component.
|
|
258
|
-
|
|
297
|
+
To do this, create a function that fetches and returns the data using `createResource`. Then pass that function to the `data` prop of the `Route` component.
|
|
259
298
|
|
|
260
299
|
```js
|
|
261
300
|
import { lazy } from "solid-js";
|
|
@@ -299,7 +338,7 @@ A common pattern is to export the data function that corresponds to a route in a
|
|
|
299
338
|
```js
|
|
300
339
|
import { lazy } from "solid-js";
|
|
301
340
|
import { Route } from "@solidjs/router";
|
|
302
|
-
import { fetchUser } ...
|
|
341
|
+
import { fetchUser } ...
|
|
303
342
|
import UserData from "./pages/users/[id].data.js";
|
|
304
343
|
const User = lazy(() => import("/pages/users/[id].js"));
|
|
305
344
|
|
|
@@ -341,15 +380,14 @@ Only leaf Route nodes (innermost `Route` components) are given a route. If you w
|
|
|
341
380
|
|
|
342
381
|
You can also take advantage of nesting by adding a parent element with an `<Outlet/>`.
|
|
343
382
|
```jsx
|
|
344
|
-
|
|
345
383
|
import { Outlet } from "@solidjs/router";
|
|
346
384
|
|
|
347
385
|
function PageWrapper () {
|
|
348
386
|
return <div>
|
|
349
|
-
|
|
387
|
+
<h1> We love our users! </h1>
|
|
350
388
|
<Outlet/>
|
|
351
|
-
|
|
352
|
-
|
|
389
|
+
<A href="/">Back Home</A>
|
|
390
|
+
</div>
|
|
353
391
|
}
|
|
354
392
|
|
|
355
393
|
<Route path="/users" component={PageWrapper}>
|
|
@@ -369,7 +407,7 @@ You can nest indefinitely - just remember that only leaf nodes will become their
|
|
|
369
407
|
</Route>
|
|
370
408
|
```
|
|
371
409
|
|
|
372
|
-
If you declare a `data` function on a parent and a child, the result of the parent's data function will be passed to the child's data function as the `data` property of the argument, as described in the last section. This works even if it isn't a direct child, because by default every route forwards its parent's data.
|
|
410
|
+
If you declare a `data` function on a parent and a child, the result of the parent's data function will be passed to the child's data function as the `data` property of the argument, as described in the last section. This works even if it isn't a direct child, because by default every route forwards its parent's data.
|
|
373
411
|
|
|
374
412
|
## Hash Mode Router
|
|
375
413
|
|
|
@@ -378,7 +416,7 @@ By default, Solid Router uses `location.pathname` as route path. You can simply
|
|
|
378
416
|
```jsx
|
|
379
417
|
import { Router, hashIntegration } from '@solidjs/router'
|
|
380
418
|
|
|
381
|
-
<Router source={hashIntegration()}><App
|
|
419
|
+
<Router source={hashIntegration()}><App /></Router>
|
|
382
420
|
```
|
|
383
421
|
|
|
384
422
|
## Config Based Routing
|
|
@@ -560,11 +598,9 @@ useBeforeLeave((e: BeforeLeaveEventArgs) => {
|
|
|
560
598
|
setTimeout(() => {
|
|
561
599
|
if (window.confirm("Discard unsaved changes - are you sure?")) {
|
|
562
600
|
// user wants to proceed anyway so retry with force=true
|
|
563
|
-
e.retry(true);
|
|
601
|
+
e.retry(true);
|
|
564
602
|
}
|
|
565
603
|
}, 100);
|
|
566
604
|
}
|
|
567
605
|
});
|
|
568
606
|
```
|
|
569
|
-
|
|
570
|
-
|
package/dist/components.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { Component, JSX } from "solid-js";
|
|
2
|
-
import type { Location, LocationChangeSignal, Navigator, RouteDataFunc, RouteDefinition, RouterIntegration } from "./types";
|
|
2
|
+
import type { Location, LocationChangeSignal, MatchFilters, Navigator, RouteDataFunc, RouteDefinition, RouterIntegration } from "./types";
|
|
3
3
|
declare module "solid-js" {
|
|
4
4
|
namespace JSX {
|
|
5
5
|
interface AnchorHTMLAttributes<T> {
|
|
@@ -10,7 +10,7 @@ declare module "solid-js" {
|
|
|
10
10
|
}
|
|
11
11
|
}
|
|
12
12
|
}
|
|
13
|
-
export
|
|
13
|
+
export type RouterProps = {
|
|
14
14
|
base?: string;
|
|
15
15
|
data?: RouteDataFunc;
|
|
16
16
|
children: JSX.Element;
|
|
@@ -29,10 +29,11 @@ export interface RoutesProps {
|
|
|
29
29
|
}
|
|
30
30
|
export declare const Routes: (props: RoutesProps) => JSX.Element;
|
|
31
31
|
export declare const useRoutes: (routes: RouteDefinition | RouteDefinition[], base?: string) => () => JSX.Element;
|
|
32
|
-
export
|
|
33
|
-
path:
|
|
32
|
+
export type RouteProps<S extends string> = {
|
|
33
|
+
path: S | S[];
|
|
34
34
|
children?: JSX.Element;
|
|
35
35
|
data?: RouteDataFunc;
|
|
36
|
+
matchFilters?: MatchFilters<S>;
|
|
36
37
|
} & ({
|
|
37
38
|
element?: never;
|
|
38
39
|
component: Component;
|
|
@@ -41,7 +42,7 @@ export declare type RouteProps = {
|
|
|
41
42
|
element?: JSX.Element;
|
|
42
43
|
preload?: () => void;
|
|
43
44
|
});
|
|
44
|
-
export declare const Route: (props: RouteProps) => JSX.Element;
|
|
45
|
+
export declare const Route: <S extends string>(props: RouteProps<S>) => JSX.Element;
|
|
45
46
|
export declare const Outlet: () => JSX.Element;
|
|
46
47
|
export interface AnchorProps extends Omit<JSX.AnchorHTMLAttributes<HTMLAnchorElement>, "state"> {
|
|
47
48
|
href: string;
|
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, normalizePath } from "./utils";
|
|
6
|
+
import { joinPaths, normalizePath, createMemoObject } 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());
|
|
@@ -16,6 +16,14 @@ export const Routes = (props) => {
|
|
|
16
16
|
const routeDefs = children(() => props.children);
|
|
17
17
|
const branches = createMemo(() => createBranches(routeDefs(), joinPaths(parentRoute.pattern, props.base || ""), Outlet));
|
|
18
18
|
const matches = createMemo(() => getRouteMatches(branches(), router.location.pathname));
|
|
19
|
+
const params = createMemoObject(() => {
|
|
20
|
+
const m = matches();
|
|
21
|
+
const params = {};
|
|
22
|
+
for (let i = 0; i < m.length; i++) {
|
|
23
|
+
Object.assign(params, m[i].params);
|
|
24
|
+
}
|
|
25
|
+
return params;
|
|
26
|
+
});
|
|
19
27
|
if (router.out) {
|
|
20
28
|
router.out.matches.push(matches().map(({ route, path, params }) => ({
|
|
21
29
|
originalPath: route.originalPath,
|
|
@@ -42,7 +50,7 @@ export const Routes = (props) => {
|
|
|
42
50
|
}
|
|
43
51
|
createRoot(dispose => {
|
|
44
52
|
disposers[i] = dispose;
|
|
45
|
-
next[i] = createRouteContext(router, next[i - 1] || parentRoute, () => routeStates()[i + 1], () => matches()[i]);
|
|
53
|
+
next[i] = createRouteContext(router, next[i - 1] || parentRoute, () => routeStates()[i + 1], () => matches()[i], params);
|
|
46
54
|
});
|
|
47
55
|
}
|
|
48
56
|
}
|
|
@@ -76,7 +84,14 @@ export const Outlet = () => {
|
|
|
76
84
|
};
|
|
77
85
|
export function A(props) {
|
|
78
86
|
props = mergeProps({ inactiveClass: "inactive", activeClass: "active" }, props);
|
|
79
|
-
const [, rest] = splitProps(props, [
|
|
87
|
+
const [, rest] = splitProps(props, [
|
|
88
|
+
"href",
|
|
89
|
+
"state",
|
|
90
|
+
"class",
|
|
91
|
+
"activeClass",
|
|
92
|
+
"inactiveClass",
|
|
93
|
+
"end"
|
|
94
|
+
]);
|
|
80
95
|
const to = useResolvedPath(() => props.href);
|
|
81
96
|
const href = useHref(to);
|
|
82
97
|
const location = useLocation();
|
package/dist/index.js
CHANGED
|
@@ -185,10 +185,7 @@ function extractSearchParams(url) {
|
|
|
185
185
|
});
|
|
186
186
|
return params;
|
|
187
187
|
}
|
|
188
|
-
function
|
|
189
|
-
return decodeURIComponent(isQuery ? str.replace(/\+/g, " ") : str);
|
|
190
|
-
}
|
|
191
|
-
function createMatcher(path, partial) {
|
|
188
|
+
function createMatcher(path, partial, matchFilters) {
|
|
192
189
|
const [pattern, splat] = path.split("/*", 2);
|
|
193
190
|
const segments = pattern.split("/").filter(Boolean);
|
|
194
191
|
const len = segments.length;
|
|
@@ -202,24 +199,46 @@ function createMatcher(path, partial) {
|
|
|
202
199
|
path: len ? "" : "/",
|
|
203
200
|
params: {}
|
|
204
201
|
};
|
|
202
|
+
const matchFilter = s => matchFilters === undefined ? undefined : matchFilters[s];
|
|
205
203
|
for (let i = 0; i < len; i++) {
|
|
206
204
|
const segment = segments[i];
|
|
207
205
|
const locSegment = locSegments[i];
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
}) !== 0) {
|
|
206
|
+
const key = segment[0] === ":" ? segment.slice(1) : segment;
|
|
207
|
+
if (segment[0] === ":" && matchSegment(locSegment, matchFilter(key))) {
|
|
208
|
+
match.params[key] = locSegment;
|
|
209
|
+
} else if (!matchSegment(locSegment, segment)) {
|
|
213
210
|
return null;
|
|
214
211
|
}
|
|
215
212
|
match.path += `/${locSegment}`;
|
|
216
213
|
}
|
|
217
214
|
if (splat) {
|
|
218
|
-
|
|
215
|
+
const remainder = lenDiff ? locSegments.slice(-lenDiff).join("/") : "";
|
|
216
|
+
if (matchSegment(remainder, matchFilter(splat))) {
|
|
217
|
+
match.params[splat] = remainder;
|
|
218
|
+
} else {
|
|
219
|
+
return null;
|
|
220
|
+
}
|
|
219
221
|
}
|
|
220
222
|
return match;
|
|
221
223
|
};
|
|
222
224
|
}
|
|
225
|
+
function matchSegment(input, filter) {
|
|
226
|
+
const isEqual = s => s.localeCompare(input, undefined, {
|
|
227
|
+
sensitivity: "base"
|
|
228
|
+
}) === 0;
|
|
229
|
+
if (filter === undefined) {
|
|
230
|
+
return true;
|
|
231
|
+
} else if (typeof filter === "string") {
|
|
232
|
+
return isEqual(filter);
|
|
233
|
+
} else if (typeof filter === "function") {
|
|
234
|
+
return filter(input);
|
|
235
|
+
} else if (Array.isArray(filter)) {
|
|
236
|
+
return filter.some(isEqual);
|
|
237
|
+
} else if (filter instanceof RegExp) {
|
|
238
|
+
return filter.test(input);
|
|
239
|
+
}
|
|
240
|
+
return false;
|
|
241
|
+
}
|
|
223
242
|
function scoreRoute(route) {
|
|
224
243
|
const [pattern, splat] = route.pattern.split("/*", 2);
|
|
225
244
|
const segments = pattern.split("/").filter(Boolean);
|
|
@@ -297,10 +316,15 @@ const useHref = to => {
|
|
|
297
316
|
const useNavigate = () => useRouter().navigatorFactory();
|
|
298
317
|
const useLocation = () => useRouter().location;
|
|
299
318
|
const useIsRouting = () => useRouter().isRouting;
|
|
300
|
-
const useMatch = path => {
|
|
319
|
+
const useMatch = (path, matchFilters) => {
|
|
301
320
|
const location = useLocation();
|
|
302
|
-
const
|
|
303
|
-
return createMemo(() =>
|
|
321
|
+
const matchers = createMemo(() => expandOptionals(path()).map(path => createMatcher(path, undefined, matchFilters)));
|
|
322
|
+
return createMemo(() => {
|
|
323
|
+
for (const matcher of matchers()) {
|
|
324
|
+
const match = matcher(location.pathname);
|
|
325
|
+
if (match) return match;
|
|
326
|
+
}
|
|
327
|
+
});
|
|
304
328
|
};
|
|
305
329
|
const useParams = () => useRoute().params;
|
|
306
330
|
const useRouteData = () => useRoute().data;
|
|
@@ -351,7 +375,7 @@ function createRoutes(routeDef, base = "", fallback) {
|
|
|
351
375
|
...shared,
|
|
352
376
|
originalPath,
|
|
353
377
|
pattern,
|
|
354
|
-
matcher: createMatcher(pattern, !isLeaf)
|
|
378
|
+
matcher: createMatcher(pattern, !isLeaf, routeDef.matchFilters)
|
|
355
379
|
});
|
|
356
380
|
}
|
|
357
381
|
return acc;
|
|
@@ -426,9 +450,9 @@ function createLocation(path, state) {
|
|
|
426
450
|
}, origin, {
|
|
427
451
|
equals: (a, b) => a.href === b.href
|
|
428
452
|
});
|
|
429
|
-
const pathname = createMemo(() =>
|
|
430
|
-
const search = createMemo(() =>
|
|
431
|
-
const hash = createMemo(() =>
|
|
453
|
+
const pathname = createMemo(() => url().pathname);
|
|
454
|
+
const search = createMemo(() => url().search, true);
|
|
455
|
+
const hash = createMemo(() => url().hash);
|
|
432
456
|
const key = createMemo(() => "");
|
|
433
457
|
return {
|
|
434
458
|
get pathname() {
|
|
@@ -612,8 +636,7 @@ function createRouterContext(integration, base = "", data, out) {
|
|
|
612
636
|
const rel = (a.getAttribute("rel") || "").split(/\s+/);
|
|
613
637
|
if (a.hasAttribute("download") || rel && rel.includes("external")) return;
|
|
614
638
|
const url = new URL(href);
|
|
615
|
-
|
|
616
|
-
if (url.origin !== window.location.origin || basePath && pathname && !pathname.toLowerCase().startsWith(basePath.toLowerCase())) return;
|
|
639
|
+
if (url.origin !== window.location.origin || basePath && url.pathname && !url.pathname.toLowerCase().startsWith(basePath.toLowerCase())) return;
|
|
617
640
|
const to = parsePath(url.pathname + url.search + url.hash);
|
|
618
641
|
const state = a.getAttribute("state");
|
|
619
642
|
evt.preventDefault();
|
|
@@ -641,7 +664,7 @@ function createRouterContext(integration, base = "", data, out) {
|
|
|
641
664
|
beforeLeave
|
|
642
665
|
};
|
|
643
666
|
}
|
|
644
|
-
function createRouteContext(router, parent, child, match) {
|
|
667
|
+
function createRouteContext(router, parent, child, match, params) {
|
|
645
668
|
const {
|
|
646
669
|
base,
|
|
647
670
|
location,
|
|
@@ -654,7 +677,6 @@ function createRouteContext(router, parent, child, match) {
|
|
|
654
677
|
data
|
|
655
678
|
} = match().route;
|
|
656
679
|
const path = createMemo(() => match().path);
|
|
657
|
-
const params = createMemoObject(() => match().params);
|
|
658
680
|
preload && preload();
|
|
659
681
|
const route = {
|
|
660
682
|
parent,
|
|
@@ -712,6 +734,14 @@ const Routes = props => {
|
|
|
712
734
|
const routeDefs = children(() => props.children);
|
|
713
735
|
const branches = createMemo(() => createBranches(routeDefs(), joinPaths(parentRoute.pattern, props.base || ""), Outlet));
|
|
714
736
|
const matches = createMemo(() => getRouteMatches(branches(), router.location.pathname));
|
|
737
|
+
const params = createMemoObject(() => {
|
|
738
|
+
const m = matches();
|
|
739
|
+
const params = {};
|
|
740
|
+
for (let i = 0; i < m.length; i++) {
|
|
741
|
+
Object.assign(params, m[i].params);
|
|
742
|
+
}
|
|
743
|
+
return params;
|
|
744
|
+
});
|
|
715
745
|
if (router.out) {
|
|
716
746
|
router.out.matches.push(matches().map(({
|
|
717
747
|
route,
|
|
@@ -741,7 +771,7 @@ const Routes = props => {
|
|
|
741
771
|
}
|
|
742
772
|
createRoot(dispose => {
|
|
743
773
|
disposers[i] = dispose;
|
|
744
|
-
next[i] = createRouteContext(router, next[i - 1] || parentRoute, () => routeStates()[i + 1], () => matches()[i]);
|
|
774
|
+
next[i] = createRouteContext(router, next[i - 1] || parentRoute, () => routeStates()[i + 1], () => matches()[i], params);
|
|
745
775
|
});
|
|
746
776
|
}
|
|
747
777
|
}
|
package/dist/routing.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { Component, Accessor } from "solid-js";
|
|
2
|
-
import type { BeforeLeaveEventArgs, Branch, Location, LocationChangeSignal, NavigateOptions, Navigator, Params, Route, RouteContext, RouteDataFunc, RouteDefinition, RouteMatch, RouterContext, RouterIntegration, SetParams } from "./types";
|
|
2
|
+
import type { BeforeLeaveEventArgs, Branch, Location, LocationChangeSignal, MatchFilters, NavigateOptions, Navigator, Params, Route, RouteContext, RouteDataFunc, RouteDefinition, RouteMatch, RouterContext, RouterIntegration, SetParams } from "./types";
|
|
3
3
|
export declare const RouterContextObj: import("solid-js").Context<RouterContext | undefined>;
|
|
4
4
|
export declare const RouteContextObj: import("solid-js").Context<RouteContext | undefined>;
|
|
5
5
|
export declare const useRouter: () => RouterContext;
|
|
@@ -9,9 +9,9 @@ export declare const useHref: (to: () => string | undefined) => Accessor<string
|
|
|
9
9
|
export declare const useNavigate: () => Navigator;
|
|
10
10
|
export declare const useLocation: <S = unknown>() => Location<S>;
|
|
11
11
|
export declare const useIsRouting: () => () => boolean;
|
|
12
|
-
export declare const useMatch: (path: () =>
|
|
12
|
+
export declare const useMatch: <S extends string>(path: () => S, matchFilters?: MatchFilters<S> | undefined) => Accessor<import("./types").PathMatch | undefined>;
|
|
13
13
|
export declare const useParams: <T extends Params>() => T;
|
|
14
|
-
|
|
14
|
+
type MaybeReturnType<T> = T extends (...args: any) => infer R ? R : T;
|
|
15
15
|
export declare const useRouteData: <T>() => MaybeReturnType<T>;
|
|
16
16
|
export declare const useSearchParams: <T extends Params>() => [T, (params: SetParams, options?: Partial<NavigateOptions>) => void];
|
|
17
17
|
export declare const useBeforeLeave: (listener: (e: BeforeLeaveEventArgs) => void) => void;
|
|
@@ -21,5 +21,5 @@ export declare function createBranches(routeDef: RouteDefinition | RouteDefiniti
|
|
|
21
21
|
export declare function getRouteMatches(branches: Branch[], location: string): RouteMatch[];
|
|
22
22
|
export declare function createLocation(path: Accessor<string>, state: Accessor<any>): Location;
|
|
23
23
|
export declare function createRouterContext(integration?: RouterIntegration | LocationChangeSignal, base?: string, data?: RouteDataFunc, out?: object): RouterContext;
|
|
24
|
-
export declare function createRouteContext(router: RouterContext, parent: RouteContext, child: () => RouteContext, match: () => RouteMatch): RouteContext;
|
|
24
|
+
export declare function createRouteContext(router: RouterContext, parent: RouteContext, child: () => RouteContext, match: () => RouteMatch, params: Params): RouteContext;
|
|
25
25
|
export {};
|
package/dist/routing.js
CHANGED
|
@@ -2,7 +2,7 @@ import { createComponent, createContext, createMemo, createRenderEffect, createS
|
|
|
2
2
|
import { isServer, delegateEvents } from "solid-js/web";
|
|
3
3
|
import { normalizeIntegration } from "./integration";
|
|
4
4
|
import { createBeforeLeave } from "./lifecycle";
|
|
5
|
-
import { createMemoObject, extractSearchParams, invariant, resolvePath, createMatcher, joinPaths, scoreRoute, mergeSearchString,
|
|
5
|
+
import { createMemoObject, extractSearchParams, invariant, resolvePath, createMatcher, joinPaths, scoreRoute, mergeSearchString, expandOptionals } from "./utils";
|
|
6
6
|
const MAX_REDIRECTS = 100;
|
|
7
7
|
export const RouterContextObj = createContext();
|
|
8
8
|
export const RouteContextObj = createContext();
|
|
@@ -23,10 +23,16 @@ export const useHref = (to) => {
|
|
|
23
23
|
export const useNavigate = () => useRouter().navigatorFactory();
|
|
24
24
|
export const useLocation = () => useRouter().location;
|
|
25
25
|
export const useIsRouting = () => useRouter().isRouting;
|
|
26
|
-
export const useMatch = (path) => {
|
|
26
|
+
export const useMatch = (path, matchFilters) => {
|
|
27
27
|
const location = useLocation();
|
|
28
|
-
const
|
|
29
|
-
return createMemo(() =>
|
|
28
|
+
const matchers = createMemo(() => expandOptionals(path()).map(path => createMatcher(path, undefined, matchFilters)));
|
|
29
|
+
return createMemo(() => {
|
|
30
|
+
for (const matcher of matchers()) {
|
|
31
|
+
const match = matcher(location.pathname);
|
|
32
|
+
if (match)
|
|
33
|
+
return match;
|
|
34
|
+
}
|
|
35
|
+
});
|
|
30
36
|
};
|
|
31
37
|
export const useParams = () => useRoute().params;
|
|
32
38
|
export const useRouteData = () => useRoute().data;
|
|
@@ -35,12 +41,20 @@ export const useSearchParams = () => {
|
|
|
35
41
|
const navigate = useNavigate();
|
|
36
42
|
const setSearchParams = (params, options) => {
|
|
37
43
|
const searchString = untrack(() => mergeSearchString(location.search, params));
|
|
38
|
-
navigate(location.pathname + searchString + location.hash, {
|
|
44
|
+
navigate(location.pathname + searchString + location.hash, {
|
|
45
|
+
scroll: false,
|
|
46
|
+
resolve: false,
|
|
47
|
+
...options
|
|
48
|
+
});
|
|
39
49
|
};
|
|
40
50
|
return [location.query, setSearchParams];
|
|
41
51
|
};
|
|
42
52
|
export const useBeforeLeave = (listener) => {
|
|
43
|
-
const s = useRouter().beforeLeave.subscribe({
|
|
53
|
+
const s = useRouter().beforeLeave.subscribe({
|
|
54
|
+
listener,
|
|
55
|
+
location: useLocation(),
|
|
56
|
+
navigate: useNavigate()
|
|
57
|
+
});
|
|
44
58
|
onCleanup(s);
|
|
45
59
|
};
|
|
46
60
|
export function createRoutes(routeDef, base = "", fallback) {
|
|
@@ -69,7 +83,7 @@ export function createRoutes(routeDef, base = "", fallback) {
|
|
|
69
83
|
...shared,
|
|
70
84
|
originalPath,
|
|
71
85
|
pattern,
|
|
72
|
-
matcher: createMatcher(pattern, !isLeaf)
|
|
86
|
+
matcher: createMatcher(pattern, !isLeaf, routeDef.matchFilters)
|
|
73
87
|
});
|
|
74
88
|
}
|
|
75
89
|
return acc;
|
|
@@ -145,9 +159,9 @@ export function createLocation(path, state) {
|
|
|
145
159
|
}, origin, {
|
|
146
160
|
equals: (a, b) => a.href === b.href
|
|
147
161
|
});
|
|
148
|
-
const pathname = createMemo(() =>
|
|
149
|
-
const search = createMemo(() =>
|
|
150
|
-
const hash = createMemo(() =>
|
|
162
|
+
const pathname = createMemo(() => url().pathname);
|
|
163
|
+
const search = createMemo(() => url().search, true);
|
|
164
|
+
const hash = createMemo(() => url().hash);
|
|
151
165
|
const key = createMemo(() => "");
|
|
152
166
|
return {
|
|
153
167
|
get pathname() {
|
|
@@ -328,9 +342,8 @@ export function createRouterContext(integration, base = "", data, out) {
|
|
|
328
342
|
if (a.hasAttribute("download") || (rel && rel.includes("external")))
|
|
329
343
|
return;
|
|
330
344
|
const url = new URL(href);
|
|
331
|
-
const pathname = urlDecode(url.pathname);
|
|
332
345
|
if (url.origin !== window.location.origin ||
|
|
333
|
-
(basePath && pathname && !pathname.toLowerCase().startsWith(basePath.toLowerCase())))
|
|
346
|
+
(basePath && url.pathname && !url.pathname.toLowerCase().startsWith(basePath.toLowerCase())))
|
|
334
347
|
return;
|
|
335
348
|
const to = parsePath(url.pathname + url.search + url.hash);
|
|
336
349
|
const state = a.getAttribute("state");
|
|
@@ -358,11 +371,10 @@ export function createRouterContext(integration, base = "", data, out) {
|
|
|
358
371
|
beforeLeave
|
|
359
372
|
};
|
|
360
373
|
}
|
|
361
|
-
export function createRouteContext(router, parent, child, match) {
|
|
374
|
+
export function createRouteContext(router, parent, child, match, params) {
|
|
362
375
|
const { base, location, navigatorFactory } = router;
|
|
363
376
|
const { pattern, element: outlet, preload, data } = match().route;
|
|
364
377
|
const path = createMemo(() => match().path);
|
|
365
|
-
const params = createMemoObject(() => match().params);
|
|
366
378
|
preload && preload();
|
|
367
379
|
const route = {
|
|
368
380
|
parent,
|
package/dist/types.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Component, JSX } from "solid-js";
|
|
2
|
-
export
|
|
3
|
-
export
|
|
2
|
+
export type Params = Record<string, string>;
|
|
3
|
+
export type SetParams = Record<string, string | number | boolean | null | undefined>;
|
|
4
4
|
export interface Path {
|
|
5
5
|
pathname: string;
|
|
6
6
|
search: string;
|
|
@@ -21,14 +21,14 @@ export interface Navigator {
|
|
|
21
21
|
(to: string, options?: Partial<NavigateOptions>): void;
|
|
22
22
|
(delta: number): void;
|
|
23
23
|
}
|
|
24
|
-
export
|
|
24
|
+
export type NavigatorFactory = (route?: RouteContext) => Navigator;
|
|
25
25
|
export interface LocationChange<S = unknown> {
|
|
26
26
|
value: string;
|
|
27
27
|
replace?: boolean;
|
|
28
28
|
scroll?: boolean;
|
|
29
29
|
state?: S;
|
|
30
30
|
}
|
|
31
|
-
export
|
|
31
|
+
export type LocationChangeSignal = [() => LocationChange, (next: LocationChange) => void];
|
|
32
32
|
export interface RouterIntegration {
|
|
33
33
|
signal: LocationChangeSignal;
|
|
34
34
|
utils?: Partial<RouterUtils>;
|
|
@@ -39,9 +39,10 @@ export interface RouteDataFuncArgs<T = unknown> {
|
|
|
39
39
|
location: Location;
|
|
40
40
|
navigate: Navigator;
|
|
41
41
|
}
|
|
42
|
-
export
|
|
43
|
-
export
|
|
44
|
-
path:
|
|
42
|
+
export type RouteDataFunc<T = unknown, R = unknown> = (args: RouteDataFuncArgs<T>) => R;
|
|
43
|
+
export type RouteDefinition<S extends string | string[] = any> = {
|
|
44
|
+
path: S;
|
|
45
|
+
matchFilters?: MatchFilters<S>;
|
|
45
46
|
data?: RouteDataFunc;
|
|
46
47
|
children?: RouteDefinition | RouteDefinition[];
|
|
47
48
|
} & ({
|
|
@@ -52,6 +53,11 @@ export declare type RouteDefinition = {
|
|
|
52
53
|
element?: JSX.Element;
|
|
53
54
|
preload?: () => void;
|
|
54
55
|
});
|
|
56
|
+
export type MatchFilter = string[] | RegExp | ((s: string) => boolean);
|
|
57
|
+
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] : [];
|
|
58
|
+
export type MatchFilters<P extends string | readonly string[] = any> = P extends string ? {
|
|
59
|
+
[K in PathParams<P>[number]]?: MatchFilter;
|
|
60
|
+
} : Record<string, MatchFilter>;
|
|
55
61
|
export interface PathMatch {
|
|
56
62
|
params: Params;
|
|
57
63
|
path: string;
|
|
@@ -73,6 +79,7 @@ export interface Route {
|
|
|
73
79
|
preload?: () => void;
|
|
74
80
|
data?: RouteDataFunc;
|
|
75
81
|
matcher: (location: string) => PathMatch | null;
|
|
82
|
+
matchFilters?: MatchFilters;
|
|
76
83
|
}
|
|
77
84
|
export interface Branch {
|
|
78
85
|
routes: Route[];
|
package/dist/utils.d.ts
CHANGED
|
@@ -1,11 +1,10 @@
|
|
|
1
|
-
import type { Params, PathMatch, Route, SetParams } from "./types";
|
|
1
|
+
import type { MatchFilters, Params, PathMatch, Route, SetParams } from "./types";
|
|
2
2
|
export declare function normalizePath(path: string, omitSlash?: boolean): string;
|
|
3
3
|
export declare function resolvePath(base: string, path: string, from?: string): string | undefined;
|
|
4
4
|
export declare function invariant<T>(value: T | null | undefined, message: string): T;
|
|
5
5
|
export declare function joinPaths(from: string, to: string): string;
|
|
6
6
|
export declare function extractSearchParams(url: URL): Params;
|
|
7
|
-
export declare function
|
|
8
|
-
export declare function createMatcher(path: string, partial?: boolean): (location: string) => PathMatch | null;
|
|
7
|
+
export declare function createMatcher<S extends string>(path: S, partial?: boolean, matchFilters?: MatchFilters<S>): (location: string) => PathMatch | null;
|
|
9
8
|
export declare function scoreRoute(route: Route): number;
|
|
10
9
|
export declare function createMemoObject<T extends Record<string | symbol, unknown>>(fn: () => T): T;
|
|
11
10
|
export declare function mergeSearchString(search: string, params: SetParams): string;
|
package/dist/utils.js
CHANGED
|
@@ -39,10 +39,7 @@ export function extractSearchParams(url) {
|
|
|
39
39
|
});
|
|
40
40
|
return params;
|
|
41
41
|
}
|
|
42
|
-
export function
|
|
43
|
-
return decodeURIComponent(isQuery ? str.replace(/\+/g, " ") : str);
|
|
44
|
-
}
|
|
45
|
-
export function createMatcher(path, partial) {
|
|
42
|
+
export function createMatcher(path, partial, matchFilters) {
|
|
46
43
|
const [pattern, splat] = path.split("/*", 2);
|
|
47
44
|
const segments = pattern.split("/").filter(Boolean);
|
|
48
45
|
const len = segments.length;
|
|
@@ -56,23 +53,50 @@ export function createMatcher(path, partial) {
|
|
|
56
53
|
path: len ? "" : "/",
|
|
57
54
|
params: {}
|
|
58
55
|
};
|
|
56
|
+
const matchFilter = (s) => matchFilters === undefined ? undefined : matchFilters[s];
|
|
59
57
|
for (let i = 0; i < len; i++) {
|
|
60
58
|
const segment = segments[i];
|
|
61
59
|
const locSegment = locSegments[i];
|
|
62
|
-
|
|
63
|
-
|
|
60
|
+
const key = segment[0] === ":" ? segment.slice(1) : segment;
|
|
61
|
+
if (segment[0] === ":" && matchSegment(locSegment, matchFilter(key))) {
|
|
62
|
+
match.params[key] = locSegment;
|
|
64
63
|
}
|
|
65
|
-
else if (
|
|
64
|
+
else if (!matchSegment(locSegment, segment)) {
|
|
66
65
|
return null;
|
|
67
66
|
}
|
|
68
67
|
match.path += `/${locSegment}`;
|
|
69
68
|
}
|
|
70
69
|
if (splat) {
|
|
71
|
-
|
|
70
|
+
const remainder = lenDiff ? locSegments.slice(-lenDiff).join("/") : "";
|
|
71
|
+
if (matchSegment(remainder, matchFilter(splat))) {
|
|
72
|
+
match.params[splat] = remainder;
|
|
73
|
+
}
|
|
74
|
+
else {
|
|
75
|
+
return null;
|
|
76
|
+
}
|
|
72
77
|
}
|
|
73
78
|
return match;
|
|
74
79
|
};
|
|
75
80
|
}
|
|
81
|
+
function matchSegment(input, filter) {
|
|
82
|
+
const isEqual = (s) => s.localeCompare(input, undefined, { sensitivity: "base" }) === 0;
|
|
83
|
+
if (filter === undefined) {
|
|
84
|
+
return true;
|
|
85
|
+
}
|
|
86
|
+
else if (typeof filter === "string") {
|
|
87
|
+
return isEqual(filter);
|
|
88
|
+
}
|
|
89
|
+
else if (typeof filter === "function") {
|
|
90
|
+
return filter(input);
|
|
91
|
+
}
|
|
92
|
+
else if (Array.isArray(filter)) {
|
|
93
|
+
return filter.some(isEqual);
|
|
94
|
+
}
|
|
95
|
+
else if (filter instanceof RegExp) {
|
|
96
|
+
return filter.test(input);
|
|
97
|
+
}
|
|
98
|
+
return false;
|
|
99
|
+
}
|
|
76
100
|
export function scoreRoute(route) {
|
|
77
101
|
const [pattern, splat] = route.pattern.split("/*", 2);
|
|
78
102
|
const segments = pattern.split("/").filter(Boolean);
|
package/package.json
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
"Ryan Turnquist"
|
|
7
7
|
],
|
|
8
8
|
"license": "MIT",
|
|
9
|
-
"version": "0.
|
|
9
|
+
"version": "0.7.0",
|
|
10
10
|
"homepage": "https://github.com/solidjs/solid-router#readme",
|
|
11
11
|
"repository": {
|
|
12
12
|
"type": "git",
|
|
@@ -28,36 +28,36 @@
|
|
|
28
28
|
"dist"
|
|
29
29
|
],
|
|
30
30
|
"sideEffects": false,
|
|
31
|
-
"scripts": {
|
|
32
|
-
"build": "tsc && rollup -c",
|
|
33
|
-
"prepublishOnly": "npm run build",
|
|
34
|
-
"test": "jest && npm run test:types",
|
|
35
|
-
"test:watch": "jest --watch",
|
|
36
|
-
"test:coverage": "jest --coverage && npm run test:types",
|
|
37
|
-
"test:types": "tsc --project tsconfig.test.json",
|
|
38
|
-
"pretty": "prettier --write \"{src,test}/**/*.{ts,tsx}\""
|
|
39
|
-
},
|
|
40
31
|
"devDependencies": {
|
|
41
32
|
"@babel/core": "^7.18.13",
|
|
42
33
|
"@babel/preset-typescript": "^7.18.6",
|
|
43
|
-
"@rollup/plugin-babel": "
|
|
44
|
-
"@rollup/plugin-node-resolve": "
|
|
34
|
+
"@rollup/plugin-babel": "6.0.3",
|
|
35
|
+
"@rollup/plugin-node-resolve": "15.0.1",
|
|
36
|
+
"@rollup/plugin-terser": "0.2.0",
|
|
45
37
|
"@types/jest": "^29.0.0",
|
|
46
38
|
"@types/node": "^18.7.14",
|
|
47
|
-
"babel-
|
|
39
|
+
"babel-jest": "^29.0.1",
|
|
40
|
+
"babel-preset-solid": "^1.6.6",
|
|
48
41
|
"jest": "^29.0.1",
|
|
49
42
|
"jest-environment-jsdom": "^29.2.1",
|
|
50
43
|
"prettier": "^2.7.1",
|
|
51
|
-
"rollup": "^
|
|
52
|
-
"rollup-plugin-terser": "^7.0.2",
|
|
44
|
+
"rollup": "^3.7.5",
|
|
53
45
|
"solid-jest": "^0.2.0",
|
|
54
|
-
"solid-js": "^1.
|
|
55
|
-
"typescript": "^4.
|
|
46
|
+
"solid-js": "^1.6.6",
|
|
47
|
+
"typescript": "^4.9.4"
|
|
56
48
|
},
|
|
57
49
|
"peerDependencies": {
|
|
58
50
|
"solid-js": "^1.5.3"
|
|
59
51
|
},
|
|
60
52
|
"jest": {
|
|
61
53
|
"preset": "solid-jest/preset/browser"
|
|
54
|
+
},
|
|
55
|
+
"scripts": {
|
|
56
|
+
"build": "tsc && rollup -c",
|
|
57
|
+
"test": "jest && npm run test:types",
|
|
58
|
+
"test:watch": "jest --watch",
|
|
59
|
+
"test:coverage": "jest --coverage && npm run test:types",
|
|
60
|
+
"test:types": "tsc --project tsconfig.test.json",
|
|
61
|
+
"pretty": "prettier --write \"{src,test}/**/*.{ts,tsx}\""
|
|
62
62
|
}
|
|
63
|
-
}
|
|
63
|
+
}
|