@pyreon/router 0.13.1 → 0.15.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 +73 -2
- package/lib/analysis/index.js.html +1 -1
- package/lib/index.js +467 -56
- package/lib/types/index.d.ts +218 -13
- package/package.json +6 -5
- package/src/components.tsx +299 -32
- package/src/env.d.ts +6 -0
- package/src/index.ts +5 -0
- package/src/loader.ts +18 -2
- package/src/manifest.ts +63 -0
- package/src/match.ts +48 -8
- package/src/not-found.ts +75 -0
- package/src/redirect.ts +63 -0
- package/src/router.ts +263 -45
- package/src/tests/loader.test.ts +149 -0
- package/src/tests/manifest-snapshot.test.ts +5 -1
- package/src/tests/match.test.ts +31 -0
- package/src/tests/native-markers.test.ts +18 -0
- package/src/tests/redirect.test.ts +96 -0
- package/src/tests/router.browser.test.tsx +68 -1
- package/src/tests/router.test.ts +686 -1
- package/src/tests/routerlink-reactive-to.browser.test.tsx +158 -0
- package/src/types.ts +95 -1
- package/lib/index.js.map +0 -1
- package/lib/types/index.d.ts.map +0 -1
package/README.md
CHANGED
|
@@ -13,9 +13,10 @@ bun add @pyreon/router
|
|
|
13
13
|
```tsx
|
|
14
14
|
import { createRouter, RouterProvider, RouterView, RouterLink } from '@pyreon/router'
|
|
15
15
|
|
|
16
|
-
|
|
16
|
+
// Type-safe named navigation — route names are checked at compile time
|
|
17
|
+
const router = createRouter<'home' | 'user'>({
|
|
17
18
|
routes: [
|
|
18
|
-
{ path: '/', component: Home },
|
|
19
|
+
{ path: '/', component: Home, name: 'home' },
|
|
19
20
|
{ path: '/user/:id', component: UserPage, name: 'user' },
|
|
20
21
|
{
|
|
21
22
|
path: '/admin',
|
|
@@ -112,3 +113,73 @@ Route changes are wrapped in `document.startViewTransition()` automatically when
|
|
|
112
113
|
| `finished` | Full animation completed | no -- `.catch()` only |
|
|
113
114
|
|
|
114
115
|
`afterEach` hooks and scroll restoration fire after the VT callback completes, so they observe the new route state when invoked.
|
|
116
|
+
|
|
117
|
+
## notFound()
|
|
118
|
+
|
|
119
|
+
Throw `notFound()` in a loader or component to render a 404 boundary:
|
|
120
|
+
|
|
121
|
+
```tsx
|
|
122
|
+
import { notFound, NotFoundBoundary, RouterView } from '@pyreon/router'
|
|
123
|
+
|
|
124
|
+
// Route loader:
|
|
125
|
+
{ path: '/user/:id', component: UserPage, loader: async ({ params }) => {
|
|
126
|
+
const user = await fetchUser(params.id)
|
|
127
|
+
if (!user) notFound()
|
|
128
|
+
return user
|
|
129
|
+
}}
|
|
130
|
+
|
|
131
|
+
// App layout:
|
|
132
|
+
<NotFoundBoundary fallback={<NotFoundPage />}>
|
|
133
|
+
<RouterView />
|
|
134
|
+
</NotFoundBoundary>
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
## Pending Components
|
|
138
|
+
|
|
139
|
+
Show a skeleton while route loaders run:
|
|
140
|
+
|
|
141
|
+
```ts
|
|
142
|
+
{
|
|
143
|
+
path: '/dashboard',
|
|
144
|
+
component: Dashboard,
|
|
145
|
+
loader: fetchDashboardData,
|
|
146
|
+
pendingComponent: DashboardSkeleton,
|
|
147
|
+
pendingMs: 200, // delay before showing skeleton (avoid flash)
|
|
148
|
+
pendingMinMs: 500, // minimum display time (avoid flicker)
|
|
149
|
+
}
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
## Validated Search Params
|
|
153
|
+
|
|
154
|
+
Type-safe query string validation per route — works with Zod, Valibot, or plain functions:
|
|
155
|
+
|
|
156
|
+
```ts
|
|
157
|
+
import { useValidatedSearch } from '@pyreon/router'
|
|
158
|
+
|
|
159
|
+
// Route config:
|
|
160
|
+
{
|
|
161
|
+
path: '/search',
|
|
162
|
+
component: SearchPage,
|
|
163
|
+
validateSearch: (raw) => ({
|
|
164
|
+
page: Number(raw.page) || 1,
|
|
165
|
+
q: raw.q ?? '',
|
|
166
|
+
}),
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
// With Zod:
|
|
170
|
+
{
|
|
171
|
+
path: '/search',
|
|
172
|
+
component: SearchPage,
|
|
173
|
+
validateSearch: z.object({
|
|
174
|
+
page: z.coerce.number().default(1),
|
|
175
|
+
q: z.string().default(''),
|
|
176
|
+
}).parse,
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
// In component:
|
|
180
|
+
const search = useValidatedSearch<{ page: number; q: string }>()
|
|
181
|
+
search().page // number — typed + validated
|
|
182
|
+
search().q // string — typed + validated
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
Structural sharing: `useValidatedSearch()` returns the same object reference when the validated values haven't changed, preventing unnecessary downstream re-renders.
|
|
@@ -5386,7 +5386,7 @@ var drawChart = (function (exports) {
|
|
|
5386
5386
|
</script>
|
|
5387
5387
|
<script>
|
|
5388
5388
|
/*<!--*/
|
|
5389
|
-
const data = {"version":2,"tree":{"name":"root","children":[{"name":"index.js","children":[{"name":"src","children":[{"uid":"
|
|
5389
|
+
const data = {"version":2,"tree":{"name":"root","children":[{"name":"index.js","children":[{"name":"src","children":[{"uid":"25bb3a92-1","name":"loader.ts"},{"uid":"25bb3a92-3","name":"match.ts"},{"uid":"25bb3a92-5","name":"redirect.ts"},{"uid":"25bb3a92-7","name":"scroll.ts"},{"uid":"25bb3a92-9","name":"types.ts"},{"uid":"25bb3a92-11","name":"router.ts"},{"uid":"25bb3a92-13","name":"components.tsx"},{"uid":"25bb3a92-15","name":"not-found.ts"},{"uid":"25bb3a92-17","name":"index.ts"}]}]}],"isRoot":true},"nodeParts":{"25bb3a92-1":{"renderedLength":3376,"gzipLength":1507,"brotliLength":0,"metaUid":"25bb3a92-0"},"25bb3a92-3":{"renderedLength":13072,"gzipLength":3951,"brotliLength":0,"metaUid":"25bb3a92-2"},"25bb3a92-5":{"renderedLength":1966,"gzipLength":1043,"brotliLength":0,"metaUid":"25bb3a92-4"},"25bb3a92-7":{"renderedLength":2194,"gzipLength":899,"brotliLength":0,"metaUid":"25bb3a92-6"},"25bb3a92-9":{"renderedLength":385,"gzipLength":246,"brotliLength":0,"metaUid":"25bb3a92-8"},"25bb3a92-11":{"renderedLength":29129,"gzipLength":8078,"brotliLength":0,"metaUid":"25bb3a92-10"},"25bb3a92-13":{"renderedLength":10571,"gzipLength":3518,"brotliLength":0,"metaUid":"25bb3a92-12"},"25bb3a92-15":{"renderedLength":1315,"gzipLength":682,"brotliLength":0,"metaUid":"25bb3a92-14"},"25bb3a92-17":{"renderedLength":0,"gzipLength":0,"brotliLength":0,"metaUid":"25bb3a92-16"}},"nodeMetas":{"25bb3a92-0":{"id":"/src/loader.ts","moduleParts":{"index.js":"25bb3a92-1"},"imported":[{"uid":"25bb3a92-18"}],"importedBy":[{"uid":"25bb3a92-16"},{"uid":"25bb3a92-12"}]},"25bb3a92-2":{"id":"/src/match.ts","moduleParts":{"index.js":"25bb3a92-3"},"imported":[],"importedBy":[{"uid":"25bb3a92-16"},{"uid":"25bb3a92-10"}]},"25bb3a92-4":{"id":"/src/redirect.ts","moduleParts":{"index.js":"25bb3a92-5"},"imported":[],"importedBy":[{"uid":"25bb3a92-16"},{"uid":"25bb3a92-10"}]},"25bb3a92-6":{"id":"/src/scroll.ts","moduleParts":{"index.js":"25bb3a92-7"},"imported":[],"importedBy":[{"uid":"25bb3a92-10"}]},"25bb3a92-8":{"id":"/src/types.ts","moduleParts":{"index.js":"25bb3a92-9"},"imported":[],"importedBy":[{"uid":"25bb3a92-16"},{"uid":"25bb3a92-10"}]},"25bb3a92-10":{"id":"/src/router.ts","moduleParts":{"index.js":"25bb3a92-11"},"imported":[{"uid":"25bb3a92-18"},{"uid":"25bb3a92-19"},{"uid":"25bb3a92-2"},{"uid":"25bb3a92-4"},{"uid":"25bb3a92-6"},{"uid":"25bb3a92-8"}],"importedBy":[{"uid":"25bb3a92-16"},{"uid":"25bb3a92-12"}]},"25bb3a92-12":{"id":"/src/components.tsx","moduleParts":{"index.js":"25bb3a92-13"},"imported":[{"uid":"25bb3a92-18"},{"uid":"25bb3a92-19"},{"uid":"25bb3a92-0"},{"uid":"25bb3a92-10"}],"importedBy":[{"uid":"25bb3a92-16"}]},"25bb3a92-14":{"id":"/src/not-found.ts","moduleParts":{"index.js":"25bb3a92-15"},"imported":[{"uid":"25bb3a92-18"}],"importedBy":[{"uid":"25bb3a92-16"}]},"25bb3a92-16":{"id":"/src/index.ts","moduleParts":{"index.js":"25bb3a92-17"},"imported":[{"uid":"25bb3a92-12"},{"uid":"25bb3a92-14"},{"uid":"25bb3a92-4"},{"uid":"25bb3a92-0"},{"uid":"25bb3a92-2"},{"uid":"25bb3a92-10"},{"uid":"25bb3a92-8"}],"importedBy":[],"isEntry":true},"25bb3a92-18":{"id":"@pyreon/core","moduleParts":{},"imported":[],"importedBy":[{"uid":"25bb3a92-12"},{"uid":"25bb3a92-14"},{"uid":"25bb3a92-0"},{"uid":"25bb3a92-10"}]},"25bb3a92-19":{"id":"@pyreon/reactivity","moduleParts":{},"imported":[],"importedBy":[{"uid":"25bb3a92-12"},{"uid":"25bb3a92-10"}]}},"env":{"rollup":"4.23.0"},"options":{"gzip":true,"brotli":false,"sourcemap":false}};
|
|
5390
5390
|
|
|
5391
5391
|
const run = () => {
|
|
5392
5392
|
const width = window.innerWidth;
|