@funstack/router 0.0.10 → 1.0.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.
@@ -0,0 +1,228 @@
1
+ import { CodeBlock } from "../components/CodeBlock.js";
2
+
3
+ export function LearnActionsPage() {
4
+ return (
5
+ <div className="learn-content">
6
+ <h2>Form Actions</h2>
7
+
8
+ <p className="page-intro">
9
+ FUNSTACK Router can intercept <code>{"<form>"}</code> submissions and
10
+ run an <strong>action</strong> function on the client before navigation
11
+ occurs. This guide explains how actions work, when to use them, and
12
+ important considerations for progressive enhancement.
13
+ </p>
14
+
15
+ <div className="callout warning">
16
+ <p className="callout-title">Important: Progressive Enhancement</p>
17
+ <p>
18
+ A <code>{'<form method="post">'}</code> should work even{" "}
19
+ <strong>before JavaScript has loaded</strong>. The browser natively
20
+ submits POST forms to the server, so your server must be prepared to
21
+ handle these requests. The router&rsquo;s <code>action</code> function
22
+ is a <strong>client-side shortcut</strong> that runs only after
23
+ hydration &mdash; it does not replace server-side form handling.
24
+ </p>
25
+ <p>
26
+ If your server cannot handle the POST request, users on slow
27
+ connections, users with JavaScript disabled, or users who submit the
28
+ form before hydration completes will experience a broken form. Always
29
+ ensure your server handles POST submissions for the same URL as a
30
+ baseline.
31
+ </p>
32
+ </div>
33
+
34
+ <section>
35
+ <h3>How It Works</h3>
36
+ <p>
37
+ When a <code>{'<form method="post">'}</code> is submitted, the router
38
+ matches the form&rsquo;s destination URL against the route
39
+ definitions. If a matched route defines an <code>action</code>, the
40
+ router intercepts the submission via the Navigation API instead of
41
+ letting the browser send it to the server. The flow is:
42
+ </p>
43
+ <ol>
44
+ <li>
45
+ User submits a form with <code>method="post"</code>
46
+ </li>
47
+ <li>
48
+ The Navigation API fires a <code>navigate</code> event with{" "}
49
+ <code>formData</code>
50
+ </li>
51
+ <li>
52
+ The router finds the deepest matched route that has an{" "}
53
+ <code>action</code>
54
+ </li>
55
+ <li>
56
+ The <code>action</code> function runs with the form data wrapped in
57
+ a <code>Request</code>
58
+ </li>
59
+ <li>
60
+ The action&rsquo;s return value is passed to the route&rsquo;s{" "}
61
+ <code>loader</code> as <code>actionResult</code>
62
+ </li>
63
+ <li>The loader runs and the UI updates with fresh data</li>
64
+ </ol>
65
+ <p>
66
+ If the matched route does <strong>not</strong> define an action, the
67
+ router does not intercept the submission and the browser sends it to
68
+ the server as a normal POST request.
69
+ </p>
70
+ </section>
71
+
72
+ <section>
73
+ <h3>Defining an Action</h3>
74
+ <p>
75
+ Add an <code>action</code> function to your route definition. It
76
+ receives an <code>ActionArgs</code> object with the route params, a{" "}
77
+ <code>Request</code>, and an <code>AbortSignal</code>:
78
+ </p>
79
+ <CodeBlock language="tsx">{`import { route } from "@funstack/router";
80
+
81
+ const editRoute = route({
82
+ path: "/posts/:postId/edit",
83
+ action: async ({ params, request, signal }) => {
84
+ const formData = await request.formData();
85
+ const title = formData.get("title") as string;
86
+ const body = formData.get("body") as string;
87
+
88
+ const res = await fetch(\`/api/posts/\${params.postId}\`, {
89
+ method: "PUT",
90
+ headers: { "Content-Type": "application/json" },
91
+ body: JSON.stringify({ title, body }),
92
+ signal,
93
+ });
94
+ return res.json();
95
+ },
96
+ loader: async ({ params, actionResult, signal }) => {
97
+ // After a successful action, actionResult contains
98
+ // the return value. On normal navigations it is undefined.
99
+ const res = await fetch(\`/api/posts/\${params.postId}\`, { signal });
100
+ return res.json();
101
+ },
102
+ component: EditPostPage,
103
+ });`}</CodeBlock>
104
+ </section>
105
+
106
+ <section>
107
+ <h3>The Form</h3>
108
+ <p>
109
+ Use a standard HTML <code>{"<form>"}</code> element with{" "}
110
+ <code>method="post"</code>. There is no special form component needed
111
+ &mdash; the router hooks into the Navigation API which intercepts
112
+ native form submissions:
113
+ </p>
114
+ <CodeBlock language="tsx">{`function EditPostPage({ data, params }: EditPostProps) {
115
+ return (
116
+ <form method="post" action={\`/posts/\${params.postId}/edit\`}>
117
+ <input name="title" defaultValue={data.title} />
118
+ <textarea name="body" defaultValue={data.body} />
119
+ <button type="submit">Save</button>
120
+ </form>
121
+ );
122
+ }`}</CodeBlock>
123
+ <p>
124
+ Note that the form&rsquo;s <code>action</code> attribute points to the
125
+ same URL that the route matches. This is essential for progressive
126
+ enhancement: before hydration, the browser will POST to this URL on
127
+ the server.
128
+ </p>
129
+ </section>
130
+
131
+ <section>
132
+ <h3>Progressive Enhancement in Detail</h3>
133
+ <p>
134
+ The action feature is designed as an{" "}
135
+ <strong>enhancement layer</strong>. The baseline behavior of a POST
136
+ form is a server round-trip, and the router&rsquo;s action provides a
137
+ faster, client-side alternative once hydration is complete. This
138
+ means:
139
+ </p>
140
+ <ul>
141
+ <li>
142
+ <strong>Before hydration</strong> &mdash; The browser submits the
143
+ form to the server as a normal POST request. Your server must handle
144
+ it and return an appropriate response (typically a redirect or a
145
+ re-rendered page).
146
+ </li>
147
+ <li>
148
+ <strong>After hydration</strong> &mdash; The router intercepts the
149
+ submission, runs your <code>action</code> function on the client,
150
+ and updates the UI without a full page reload.
151
+ </li>
152
+ </ul>
153
+ <p>
154
+ Both paths should produce the same end result for the user. The client
155
+ action is a shortcut, not a replacement.
156
+ </p>
157
+
158
+ <div className="callout warning">
159
+ <p className="callout-title">
160
+ When your server cannot handle POST requests
161
+ </p>
162
+ <p>
163
+ If you are building a purely client-side application (e.g. a SPA
164
+ with no server-side form handling), consider using React 19&rsquo;s{" "}
165
+ <code>{"<form action={fn}>"}</code> pattern instead. When a form
166
+ action is a <strong>function</strong> rather than a URL, the browser
167
+ will not attempt a server round-trip on submission. Note that in a
168
+ client-only app the form will not work until React hydrates, since
169
+ the function only exists in the JavaScript bundle.
170
+ </p>
171
+ <p>
172
+ In contrast, FUNSTACK Router&rsquo;s <code>action</code> intercepts
173
+ URL-based form submissions. If the client has not hydrated yet, the
174
+ browser will POST to the URL, which will fail without server
175
+ handling.
176
+ </p>
177
+ </div>
178
+ </section>
179
+
180
+ <section>
181
+ <h3>Action Result and Loader</h3>
182
+ <p>
183
+ When a route defines both an <code>action</code> and a{" "}
184
+ <code>loader</code>, the loader runs after the action completes. The
185
+ action&rsquo;s return value is passed to the loader via the{" "}
186
+ <code>actionResult</code> parameter:
187
+ </p>
188
+ <CodeBlock language="typescript">{`action: async ({ request }) => {
189
+ const formData = await request.formData();
190
+ // ... process form
191
+ return { success: true, message: "Saved!" };
192
+ },
193
+ loader: async ({ params, actionResult, signal }) => {
194
+ // actionResult is { success: true, message: "Saved!" }
195
+ // after the action, or undefined on normal navigation
196
+ const data = await fetchData(params.id, signal);
197
+ return { ...data, actionResult };
198
+ },`}</CodeBlock>
199
+ <p>
200
+ This lets your UI display feedback from the action (e.g. success
201
+ messages or validation errors) alongside the refreshed data.
202
+ </p>
203
+ </section>
204
+
205
+ <section>
206
+ <h3>Summary</h3>
207
+ <ul>
208
+ <li>
209
+ <code>action</code> intercepts POST form submissions on the client
210
+ after hydration
211
+ </li>
212
+ <li>
213
+ Your server must handle the same POST endpoint for progressive
214
+ enhancement
215
+ </li>
216
+ <li>
217
+ The action&rsquo;s return value flows to the loader as{" "}
218
+ <code>actionResult</code>
219
+ </li>
220
+ <li>
221
+ For SPAs without server-side form handling, prefer React 19&rsquo;s{" "}
222
+ <code>{"<form action={fn}>"}</code> pattern
223
+ </li>
224
+ </ul>
225
+ </section>
226
+ </div>
227
+ );
228
+ }
@@ -210,7 +210,7 @@ function App() {
210
210
  Ephemeral <code>info</code>
211
211
  </strong>{" "}
212
212
  &mdash; Pass non-persisted context data during navigation via{" "}
213
- <code>navigation.navigate(url, {"{ info }"}))</code>
213
+ <code>navigation.navigate(url, {"{ info }"})</code>
214
214
  </li>
215
215
  <li>
216
216
  <strong>navigation.entries()</strong> &mdash; Access the full
@@ -0,0 +1,285 @@
1
+ import { CodeBlock } from "../components/CodeBlock.js";
2
+
3
+ export function LearnRouteDefinitionsPage() {
4
+ return (
5
+ <div className="learn-content">
6
+ <h2>RSC with Route Features</h2>
7
+
8
+ <p className="page-intro">
9
+ When using React Server Components as route components, you may also
10
+ want route features like loaders, typed hooks (
11
+ <code>useRouteParams</code>, <code>useRouteData</code>), and navigation
12
+ state. The challenge is that route definitions referencing server
13
+ components cannot be imported from client modules. This guide shows how
14
+ to split a route definition into a <strong>shared part</strong>{" "}
15
+ (importable by client components for type safety) and a{" "}
16
+ <strong>server part</strong> (where the component is attached), enabling
17
+ full route features alongside RSC.
18
+ </p>
19
+
20
+ <section>
21
+ <h3>The Problem</h3>
22
+ <p>
23
+ In an RSC architecture, server modules and client modules cannot
24
+ freely import from each other. This creates a dilemma for type-safe
25
+ routing:
26
+ </p>
27
+ <ul>
28
+ <li>
29
+ <strong>If routes live in a server module</strong> &mdash; they can
30
+ reference server components, but client components cannot import the
31
+ route objects for type-safe hooks like <code>useRouteParams</code>{" "}
32
+ or <code>useRouteData</code>.
33
+ </li>
34
+ <li>
35
+ <strong>If routes live in a shared module</strong> &mdash; client
36
+ components can import them, but server components cannot be
37
+ referenced (importing a server component makes a module
38
+ server-only).
39
+ </li>
40
+ </ul>
41
+ <p>
42
+ There is no single location where route objects can both reference
43
+ server components <em>and</em> be imported by client components.
44
+ </p>
45
+ </section>
46
+
47
+ <section>
48
+ <h3>The Key Insight</h3>
49
+ <p>
50
+ The only part of a route definition that is inherently server-specific
51
+ is the <strong>component</strong> (because it may be a server
52
+ component). Everything else &mdash; <code>id</code>, <code>path</code>
53
+ , <code>loader</code>, <code>action</code>, and navigation state
54
+ &mdash; is client-safe. Loaders and actions run in the browser during
55
+ navigation, so they can live in shared modules.
56
+ </p>
57
+ <p>
58
+ This means we can split a route definition at exactly one point: the
59
+ component reference. FUNSTACK Router supports this split through
60
+ partial route definitions and <code>bindRoute()</code>.
61
+ </p>
62
+ </section>
63
+
64
+ <section>
65
+ <h3>Step 1: Define the Route (Shared Module)</h3>
66
+ <p>
67
+ Call <code>route()</code> <strong>without</strong> a{" "}
68
+ <code>component</code> property to create a partial route definition.
69
+ This object carries all type information and is safe to import from
70
+ client modules:
71
+ </p>
72
+ <CodeBlock language="typescript">{`// src/pages/user/loader.ts
73
+ "use client";
74
+ import type { User } from "../../types";
75
+
76
+ export async function loadUser({ params, signal }) {
77
+ const res = await fetch(\`/api/users/\${params.userId}\`, { signal });
78
+ return res.json() as Promise<User>;
79
+ }`}</CodeBlock>
80
+ <CodeBlock language="typescript">{`// src/pages/user/route.ts — shared module (no "use client" directive)
81
+ import { route } from "@funstack/router/server";
82
+ import { loadUser } from "./loader";
83
+
84
+ export const userRoute = route({
85
+ id: "user",
86
+ path: "/:userId",
87
+ loader: loadUser,
88
+ });
89
+ // Inferred types:
90
+ // Params = { userId: string } — from path
91
+ // Data = User — from loader return type`}</CodeBlock>
92
+ <p>
93
+ The <code>id</code> property is required for partial routes &mdash; it
94
+ is used at runtime to match the route context and at the type level to
95
+ carry type information for hooks.
96
+ </p>
97
+ </section>
98
+
99
+ <section>
100
+ <h3>Step 2: Bind the Component (Server Module)</h3>
101
+ <p>
102
+ Use <code>bindRoute()</code> from <code>@funstack/router/server</code>{" "}
103
+ to attach a component to the partial route. This produces a full route
104
+ definition for <code>{"<Router />"}</code>:
105
+ </p>
106
+ <CodeBlock language="tsx">{`// src/App.tsx — Server Component
107
+ import { bindRoute } from "@funstack/router/server";
108
+ import { Router } from "@funstack/router";
109
+ import { userRoute } from "./pages/user/route";
110
+ import { UserProfile } from "./pages/user/UserProfile";
111
+
112
+ const routes = [
113
+ bindRoute(userRoute, {
114
+ component: <UserProfile />,
115
+ }),
116
+ ];
117
+
118
+ export default function App() {
119
+ return <Router routes={routes} />;
120
+ }`}</CodeBlock>
121
+ <p>
122
+ Because <code>bindRoute()</code> lives in the server entry point, the
123
+ component can be a server component. The resulting route definition is
124
+ fully compatible with <code>{"<Router />"}</code> &mdash; it is the
125
+ same type as what <code>route()</code> with a component produces.
126
+ </p>
127
+ <p>
128
+ <code>bindRoute()</code> also accepts optional <code>children</code>,{" "}
129
+ <code>exact</code>, and <code>requireChildren</code> properties in the
130
+ second argument, just like the regular <code>route()</code> function.
131
+ </p>
132
+ </section>
133
+
134
+ <section>
135
+ <h3>Type-Safe Hooks in Client Components</h3>
136
+ <p>
137
+ The partial route object from Step 1 can be imported in client
138
+ components and passed to hooks for full type safety:
139
+ </p>
140
+ <CodeBlock language="tsx">{`// src/pages/user/UserActions.tsx
141
+ "use client";
142
+ import { useRouteParams, useRouteData } from "@funstack/router";
143
+ import { userRoute } from "./route";
144
+
145
+ export function UserActions() {
146
+ const { userId } = useRouteParams(userRoute);
147
+ // userId: string ✓
148
+
149
+ const user = useRouteData(userRoute);
150
+ // user: User ✓
151
+
152
+ return (
153
+ <div>
154
+ <h2>{user.name}</h2>
155
+ <p>User ID: {userId}</p>
156
+ </div>
157
+ );
158
+ }`}</CodeBlock>
159
+ <p>
160
+ All typed hooks &mdash; <code>useRouteParams</code>,{" "}
161
+ <code>useRouteData</code>, and <code>useRouteState</code> &mdash;
162
+ accept both partial route definitions and full route definitions. The
163
+ type information flows naturally from path patterns, loader return
164
+ types, and <code>routeState</code>.
165
+ </p>
166
+ </section>
167
+
168
+ <section>
169
+ <h3>Navigation State</h3>
170
+ <p>
171
+ <code>routeState()</code> also supports partial route definitions.
172
+ When called without a <code>component</code>, it produces a partial
173
+ route carrying the state type:
174
+ </p>
175
+ <CodeBlock language="typescript">{`// src/pages/settings/route.ts — shared module
176
+ import { routeState } from "@funstack/router/server";
177
+
178
+ type SettingsState = { tab: string };
179
+
180
+ export const settingsRoute = routeState<SettingsState>()({
181
+ id: "settings",
182
+ path: "/settings",
183
+ });
184
+ // Params = {}, State = { tab: string }`}</CodeBlock>
185
+ <CodeBlock language="tsx">{`// src/pages/settings/SettingsPanel.tsx
186
+ "use client";
187
+ import { useRouteState } from "@funstack/router";
188
+ import { settingsRoute } from "./route";
189
+
190
+ export function SettingsPanel() {
191
+ const state = useRouteState(settingsRoute);
192
+ // state: { tab: string } | undefined ✓
193
+ // ...
194
+ }`}</CodeBlock>
195
+ </section>
196
+
197
+ <section>
198
+ <h3>Nested Routes</h3>
199
+ <p>
200
+ Partial routes use relative path segments, the same as regular routes.
201
+ Use <code>bindRoute()</code> with <code>children</code> to build
202
+ nested route trees:
203
+ </p>
204
+ <CodeBlock language="typescript">{`// src/pages/users/route.ts
205
+ import { route } from "@funstack/router/server";
206
+ export const usersRoute = route({ id: "users", path: "/users" });
207
+
208
+ // src/pages/users/profile/route.ts
209
+ import { route } from "@funstack/router/server";
210
+ import { fetchUser } from "./fetchUser"; // "use client" module
211
+ export const userProfileRoute = route({
212
+ id: "userProfile",
213
+ path: "/:userId", // relative to parent
214
+ loader: fetchUser,
215
+ });
216
+
217
+ // src/pages/users/settings/route.ts
218
+ import { route } from "@funstack/router/server";
219
+ export const userSettingsRoute = route({
220
+ id: "userSettings",
221
+ path: "/:userId/settings", // relative to parent
222
+ });`}</CodeBlock>
223
+ <CodeBlock language="tsx">{`// src/App.tsx
224
+ const routes = [
225
+ bindRoute(usersRoute, {
226
+ component: <Outlet />,
227
+ children: [
228
+ bindRoute(userProfileRoute, {
229
+ component: <UserProfile />,
230
+ }),
231
+ bindRoute(userSettingsRoute, {
232
+ component: <UserSettings />,
233
+ }),
234
+ ],
235
+ }),
236
+ ];`}</CodeBlock>
237
+ <p>
238
+ For layout routes that don't need typed hooks, <code>id</code> is
239
+ optional. A route without <code>id</code> can still be used with{" "}
240
+ <code>bindRoute()</code>:
241
+ </p>
242
+ <CodeBlock language="typescript">{`import { route, bindRoute } from "@funstack/router/server";
243
+ const layout = route({ path: "/dashboard" });
244
+ bindRoute(layout, { component: <Outlet />, children: [...] });`}</CodeBlock>
245
+ </section>
246
+
247
+ <section>
248
+ <h3>Recommended Project Structure</h3>
249
+ <p>
250
+ This pattern encourages <strong>collocating</strong> each route
251
+ definition with the page components that use it:
252
+ </p>
253
+ <CodeBlock language="bash">{`src/
254
+ pages/
255
+ user/
256
+ route.ts ← Step 1: id, path (shared module)
257
+ loader.ts ← "use client" — loader function
258
+ UserProfile.tsx ← Server component (the page)
259
+ UserActions.tsx ← "use client" — imports ./route for hooks
260
+ settings/
261
+ route.ts ← Step 1: id, path, routeState (shared module)
262
+ Settings.tsx ← Server component (the page)
263
+ SettingsPanel.tsx ← "use client" — imports ./route for hooks
264
+ App.tsx ← Step 2: bindRoute() assembles route tree`}</CodeBlock>
265
+ <p>This structure provides several benefits:</p>
266
+ <ul>
267
+ <li>
268
+ <strong>Locality</strong> &mdash; The route definition sits next to
269
+ the components that use it. Imports are short and obvious.
270
+ </li>
271
+ <li>
272
+ <strong>Encapsulation</strong> &mdash; Each page "owns" its route.
273
+ Adding a new page means adding a folder with a route and components,
274
+ then one <code>bindRoute()</code> call in <code>App.tsx</code>.
275
+ </li>
276
+ <li>
277
+ <strong>Local type safety</strong> &mdash; Path params and loader
278
+ data types are defined once in <code>route.ts</code> and consumed by
279
+ sibling client components. No separate type declarations needed.
280
+ </li>
281
+ </ul>
282
+ </section>
283
+ </div>
284
+ );
285
+ }
@@ -269,6 +269,12 @@ export default function App() {
269
269
  See also the <a href="/learn/ssr">Server-Side Rendering</a> guide
270
270
  for how the router handles SSR and hydration
271
271
  </li>
272
+ <li>
273
+ For type-safe hooks in client components, see the{" "}
274
+ <a href="/learn/rsc/route-features">RSC with Route Features</a>{" "}
275
+ guide which explains how to split route definitions across the
276
+ server/client boundary
277
+ </li>
272
278
  </ul>
273
279
  </section>
274
280
  </div>
@@ -103,11 +103,9 @@ export function LearnSsgPage() {
103
103
  </p>
104
104
  <p>
105
105
  If you only need loaders to run at build time (not on the client),
106
- consider using{" "}
107
- <a href="/learn/react-server-components">React Server Components</a>{" "}
108
- with SSG. RSC lets you fetch data on the server during the build and
109
- send the result as static HTML, without shipping loader code to the
110
- client.
106
+ consider using <a href="/learn/rsc">React Server Components</a> with
107
+ SSG. RSC lets you fetch data on the server during the build and send
108
+ the result as static HTML, without shipping loader code to the client.
111
109
  </p>
112
110
  </section>
113
111
 
@@ -3,6 +3,7 @@
3
3
  ## Available Documentation
4
4
 
5
5
  - [Examples](./ExamplesPage.tsx)
6
+ - [FAQ](./FaqPage.tsx)
6
7
  - [Getting Started](./GettingStartedPage.tsx)
7
8
 
8
9
  ### API Reference
@@ -14,8 +15,10 @@
14
15
 
15
16
  ### Learn
16
17
 
18
+ - [Form Actions](./LearnActionsPage.tsx) - FUNSTACK Router can intercept submissions and run an action function on the client before navigation occurs. This guide explains how actions work, when to use them, and important considerations for progressive enhancement.
17
19
  - [Navigation API](./LearnNavigationApiPage.tsx) - FUNSTACK Router is built on the Navigation API , a modern browser API that provides a unified way to handle navigation. This guide explains the key differences from the older History API and the benefits this brings to your application.
18
20
  - [Nested Routes](./LearnNestedRoutesPage.tsx) - Nested routes let you build complex page layouts where parts of the UI persist across navigation while other parts change. Think of a dashboard with a sidebar that stays in place while the main content area updates&mdash;that's nested routing in action.
21
+ - [RSC with Route Features](./LearnRouteDefinitionsPage.tsx) - When using React Server Components as route components, you may also want route features like loaders, typed hooks ( useRouteParams, useRouteData), and navigation state. The challenge is that route definitions referencing server components cannot be imported from client modules. This guide shows how to split a route definition into a shared part (importable by client components for type safety) and a server part (where the component is attached), enabling full route features alongside RSC.
19
22
  - [React Server Components](./LearnRscPage.tsx) - FUNSTACK Router is designed to work with React Server Components (RSC). The package provides a dedicated server entry point so that route definitions can live in server modules, keeping client bundle sizes small.
20
23
  - [Static Site Generation](./LearnSsgPage.tsx) - When your server or static site generator knows the URL being rendered, you can use the ssr prop to match path-based routes during SSR. This produces richer server-rendered HTML &mdash; users see page content immediately instead of just the app shell.
21
24
  - [How SSR Works](./LearnSsrBasicPage.tsx) - FUNSTACK Router supports server-side rendering with a two-stage model. During SSR, pathless (layout) routes without loaders render to produce an app shell, while path-based routes and loaders activate only after client hydration.
package/dist/index.d.mts CHANGED
@@ -1,4 +1,4 @@
1
- import { a as ExtractRouteState, c as PathParams, d as RouteComponentPropsWithData, f as RouteDefinition, h as routeState, i as ExtractRouteParams, l as RouteComponentProps, m as route, n as ExtractRouteData, o as LoaderArgs, p as TypefulOpaqueRouteDefinition, r as ExtractRouteId, s as OpaqueRouteDefinition, t as ActionArgs, u as RouteComponentPropsOf } from "./route-DRcgs0Pt.mjs";
1
+ import { _ as routeState, a as ExtractRouteParams, c as OpaqueRouteDefinition, d as RouteComponentProps, f as RouteComponentPropsOf, g as route, h as TypefulOpaqueRouteDefinition, i as ExtractRouteId, l as PartialRouteDefinition, m as RouteDefinition, n as ActionArgs, o as ExtractRouteState, p as RouteComponentPropsWithData, r as ExtractRouteData, s as LoaderArgs, t as bindRoute, u as PathParams } from "./bindRoute-BtT4qPKI.mjs";
2
2
  import { ComponentType, ReactNode } from "react";
3
3
 
4
4
  //#region src/types.d.ts
@@ -167,12 +167,6 @@ declare function Router({
167
167
  */
168
168
  declare function Outlet(): ReactNode;
169
169
  //#endregion
170
- //#region src/hooks/useNavigate.d.ts
171
- /**
172
- * Returns a function for programmatic navigation.
173
- */
174
- declare function useNavigate(): (to: string, options?: NavigateOptions) => void;
175
- //#endregion
176
170
  //#region src/hooks/useLocation.d.ts
177
171
  /**
178
172
  * Returns the current location object.
@@ -244,7 +238,7 @@ declare function useBlocker(options: UseBlockerOptions): void;
244
238
  * }
245
239
  * ```
246
240
  */
247
- declare function useRouteParams<T extends TypefulOpaqueRouteDefinition<string, Record<string, string>, unknown, unknown>>(route: T): ExtractRouteParams<T>;
241
+ declare function useRouteParams<T extends TypefulOpaqueRouteDefinition<string, Record<string, string>, unknown, unknown> | PartialRouteDefinition<string, Record<string, string>, unknown, unknown>>(route: T): ExtractRouteParams<T>;
248
242
  //#endregion
249
243
  //#region src/hooks/useRouteState.d.ts
250
244
  /**
@@ -268,7 +262,7 @@ declare function useRouteParams<T extends TypefulOpaqueRouteDefinition<string, R
268
262
  * }
269
263
  * ```
270
264
  */
271
- declare function useRouteState<T extends TypefulOpaqueRouteDefinition<string, Record<string, string>, unknown, unknown>>(route: T): ExtractRouteState<T> | undefined;
265
+ declare function useRouteState<T extends TypefulOpaqueRouteDefinition<string, Record<string, string>, unknown, unknown> | PartialRouteDefinition<string, Record<string, string>, unknown, unknown>>(route: T): ExtractRouteState<T> | undefined;
272
266
  //#endregion
273
267
  //#region src/hooks/useRouteData.d.ts
274
268
  /**
@@ -295,7 +289,7 @@ declare function useRouteState<T extends TypefulOpaqueRouteDefinition<string, Re
295
289
  * }
296
290
  * ```
297
291
  */
298
- declare function useRouteData<T extends TypefulOpaqueRouteDefinition<string, Record<string, string>, unknown, unknown>>(route: T): ExtractRouteData<T>;
292
+ declare function useRouteData<T extends TypefulOpaqueRouteDefinition<string, Record<string, string>, unknown, unknown> | PartialRouteDefinition<string, Record<string, string>, unknown, unknown>>(route: T): ExtractRouteData<T>;
299
293
  //#endregion
300
294
  //#region src/hooks/useIsPending.d.ts
301
295
  /**
@@ -303,5 +297,16 @@ declare function useRouteData<T extends TypefulOpaqueRouteDefinition<string, Rec
303
297
  */
304
298
  declare function useIsPending(): boolean;
305
299
  //#endregion
306
- export { type ActionArgs, type ExtractRouteData, type ExtractRouteId, type ExtractRouteParams, type ExtractRouteState, type FallbackMode, type LoaderArgs, type Location, type MatchedRoute, type NavigateOptions, type OnNavigateCallback, type OnNavigateInfo, type OpaqueRouteDefinition, Outlet, type PathParams, type RouteComponentProps, type RouteComponentPropsOf, type RouteComponentPropsWithData, type RouteDefinition, Router, type RouterProps, type SSRConfig, type TypefulOpaqueRouteDefinition, type UseBlockerOptions, route, routeState, useBlocker, useIsPending, useLocation, useNavigate, useRouteData, useRouteParams, useRouteState, useSearchParams };
300
+ //#region src/bypassInterception.d.ts
301
+ /**
302
+ * Perform a full page reload, bypassing the router's interception.
303
+ */
304
+ declare function hardReload(): void;
305
+ /**
306
+ * Navigate to the given URL with a full page navigation,
307
+ * bypassing the router's interception.
308
+ */
309
+ declare function hardNavigate(url: string): void;
310
+ //#endregion
311
+ export { type ActionArgs, type ExtractRouteData, type ExtractRouteId, type ExtractRouteParams, type ExtractRouteState, type FallbackMode, type LoaderArgs, type Location, type MatchedRoute, type NavigateOptions, type OnNavigateCallback, type OnNavigateInfo, type OpaqueRouteDefinition, Outlet, type PartialRouteDefinition, type PathParams, type RouteComponentProps, type RouteComponentPropsOf, type RouteComponentPropsWithData, type RouteDefinition, Router, type RouterProps, type SSRConfig, type TypefulOpaqueRouteDefinition, type UseBlockerOptions, bindRoute, hardNavigate, hardReload, route, routeState, useBlocker, useIsPending, useLocation, useRouteData, useRouteParams, useRouteState, useSearchParams };
307
312
  //# sourceMappingURL=index.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.mts","names":[],"sources":["../src/types.ts","../src/Router/index.tsx","../src/Outlet.tsx","../src/hooks/useNavigate.ts","../src/hooks/useLocation.ts","../src/hooks/useSearchParams.ts","../src/hooks/useBlocker.ts","../src/hooks/useRouteParams.ts","../src/hooks/useRouteState.ts","../src/hooks/useRouteData.ts","../src/hooks/useIsPending.ts"],"mappings":";;;;cAGM,6BAAA;;AAFoE;;;;;;;KAgB9D,uBAAA;EAAA,CACT,6BAAA,UAyB0B;EAvB3B,IAAA,WA4Be;EA1Bf,QAAA,GAAW,uBAAA;EAgCc;;;;;;EAzBzB,KAAA;EAPA;;;;;EAaA,eAAA,YAM2B;EAA3B,MAAA,IAAU,IAAA,EAAM,UAAA,CAAW,MAAA,+BAE3B;EAAA,MAAA,IAAU,IAAA,EAAM,UAAA,CAAW,MAAA,wCAAA;EAE3B,SAAA,GACI,aAAA;IACE,IAAA;IACA,MAAA,GAAS,MAAA;IACT,KAAA;IACA,QAAA,IACE,KAAA,cAAmB,IAAA,2BAChB,OAAA;IACL,YAAA,IAAgB,KAAA,cAAmB,IAAA;IACnC,UAAA,SAAmB,OAAA;IACnB,cAAA;IACA,IAAA;EAAA,KAEF,SAAA;AAAA;;;AAmBN;KAAY,YAAA;sCAEV,KAAA,EAAO,uBAAA,EAAP;EAEA,MAAA,EAAQ,MAAA,kBAAR;EAEA,QAAA;AAAA;;;;KAcU,cAAA;EAMQ,4DAJlB,OAAA,WAAkB,YAAA,WAUR;EARV,YAAA;EAEA,QAAA,EAAU,QAAA;AAAA;;;;KAMA,eAAA;EAYA,uDAVV,OAAA;EAEA,KAAA,YASA;EAPA,IAAA;AAAA;;;AAmBF;KAbY,QAAA;EACV,QAAA;EACA,MAAA;EACA,IAAA;AAAA;;;;;AAqBF;;;KAXY,kBAAA,IACV,KAAA,EAAO,aAAA,EACP,IAAA,EAAM,cAAA;;;;;ACjGR;;KD0GY,YAAA;;;;AAhJ8D;;KCsC9D,SAAA;EDpCkC;;AAc9C;;;;EC6BE,IAAA;EDL2B;;;;;;;;;;;ECiB3B,UAAA;AAAA;AAAA,KAGU,WAAA;EACV,MAAA,EAAQ,eAAA;EDjCR;;;;;;;ECyCA,UAAA,GAAa,kBAAA;ED3Bc;;;;;;ECkC3B,QAAA,GAAW,YAAA;ED5BL;;;;;;;;;;;;;;;AA4BR;;;;;ECqBE,GAAA,GAAM,SAAA;AAAA;AAAA,iBAGQ,MAAA,CAAA;EACd,MAAA,EAAQ,WAAA;EACR,UAAA;EACA,QAAA;EACA;AAAA,GACC,WAAA,GAAc,SAAA;;;;;;ADzGyD;iBEM1D,MAAA,CAAA,GAAU,SAAA;;;;;;iBCAV,WAAA,CAAA,IAAgB,EAAA,UAAY,OAAA,GAAU,eAAA;;;;;;iBCAtC,WAAA,CAAA,GAAe,QAAA;;;KCJ1B,eAAA,IACH,MAAA,EACI,eAAA,GACA,MAAA,qBACE,IAAA,EAAM,eAAA,KAAoB,eAAA,GAAkB,MAAA;;;;iBAMpC,eAAA,CAAA,IAAoB,eAAA,EAAiB,eAAA;;;KCVzC,iBAAA;;;;ANF8D;EMOxE,WAAA;AAAA;;;ANSF;;;;;;;;;;;;;;;;;;;;;;;;;iBMqBgB,UAAA,CAAW,OAAA,EAAS,iBAAA;;;;;;ANrCsC;;;;;AAgB1E;;;;;;;;;;;;iBOSgB,cAAA,WACJ,4BAAA,SAER,MAAA,oCAAA,CAIF,KAAA,EAAO,CAAA,GAAI,kBAAA,CAAmB,CAAA;;;;;;APhC0C;;;;;AAgB1E;;;;;;;;;;;;;iBQUgB,aAAA,WACJ,4BAAA,SAER,MAAA,oCAAA,CAIF,KAAA,EAAO,CAAA,GAAI,iBAAA,CAAkB,CAAA;;;;;;ARjC2C;;;;;AAgB1E;;;;;;;;;;;;;;;;iBSagB,YAAA,WACJ,4BAAA,SAER,MAAA,oCAAA,CAIF,KAAA,EAAO,CAAA,GAAI,gBAAA,CAAiB,CAAA;;;;;;iBC/Bd,YAAA,CAAA"}
1
+ {"version":3,"file":"index.d.mts","names":[],"sources":["../src/types.ts","../src/Router/index.tsx","../src/Outlet.tsx","../src/hooks/useLocation.ts","../src/hooks/useSearchParams.ts","../src/hooks/useBlocker.ts","../src/hooks/useRouteParams.ts","../src/hooks/useRouteState.ts","../src/hooks/useRouteData.ts","../src/hooks/useIsPending.ts","../src/bypassInterception.ts"],"mappings":";;;;cAGM,6BAAA;;AAFoE;;;;;;;KAgB9D,uBAAA;EAAA,CACT,6BAAA,UAyB0B;EAvB3B,IAAA,WA4Be;EA1Bf,QAAA,GAAW,uBAAA;EAgCc;;;;;;EAzBzB,KAAA;EAPA;;;;;EAaA,eAAA,YAM2B;EAA3B,MAAA,IAAU,IAAA,EAAM,UAAA,CAAW,MAAA,+BAE3B;EAAA,MAAA,IAAU,IAAA,EAAM,UAAA,CAAW,MAAA,wCAAA;EAE3B,SAAA,GACI,aAAA;IACE,IAAA;IACA,MAAA,GAAS,MAAA;IACT,KAAA;IACA,QAAA,IACE,KAAA,cAAmB,IAAA,2BAChB,OAAA;IACL,YAAA,IAAgB,KAAA,cAAmB,IAAA;IACnC,UAAA,SAAmB,OAAA;IACnB,cAAA;IACA,IAAA;EAAA,KAEF,SAAA;AAAA;;;AAmBN;KAAY,YAAA;sCAEV,KAAA,EAAO,uBAAA,EAAP;EAEA,MAAA,EAAQ,MAAA,kBAAR;EAEA,QAAA;AAAA;;;;KAcU,cAAA;EAMQ,4DAJlB,OAAA,WAAkB,YAAA,WAUR;EARV,YAAA;EAEA,QAAA,EAAU,QAAA;AAAA;;;;KAMA,eAAA;EAYA,uDAVV,OAAA;EAEA,KAAA,YASA;EAPA,IAAA;AAAA;;;AAmBF;KAbY,QAAA;EACV,QAAA;EACA,MAAA;EACA,IAAA;AAAA;;;;;AAqBF;;;KAXY,kBAAA,IACV,KAAA,EAAO,aAAA,EACP,IAAA,EAAM,cAAA;;;;;AChGR;;KDyGY,YAAA;;;;AAhJ8D;;KCuC9D,SAAA;EDrCkC;;AAc9C;;;;EC8BE,IAAA;EDN2B;;;;;;;;;;;ECkB3B,UAAA;AAAA;AAAA,KAGU,WAAA;EACV,MAAA,EAAQ,eAAA;EDlCR;;;;;;;EC0CA,UAAA,GAAa,kBAAA;ED5Bc;;;;;;ECmC3B,QAAA,GAAW,YAAA;ED7BL;;;;;;;;;;;;;;;AA4BR;;;;;ECsBE,GAAA,GAAM,SAAA;AAAA;AAAA,iBAGQ,MAAA,CAAA;EACd,MAAA,EAAQ,WAAA;EACR,UAAA;EACA,QAAA;EACA;AAAA,GACC,WAAA,GAAc,SAAA;;;;;;AD1GyD;iBEM1D,MAAA,CAAA,GAAU,SAAA;;;;;;iBCAV,WAAA,CAAA,GAAe,QAAA;;;KCJ1B,eAAA,IACH,MAAA,EACI,eAAA,GACA,MAAA,qBACE,IAAA,EAAM,eAAA,KAAoB,eAAA,GAAkB,MAAA;;;;iBAMpC,eAAA,CAAA,IAAoB,eAAA,EAAiB,eAAA;;;KCVzC,iBAAA;;;;ALF8D;EKOxE,WAAA;AAAA;;;ALSF;;;;;;;;;;;;;;;;;;;;;;;;;iBKqBgB,UAAA,CAAW,OAAA,EAAS,iBAAA;;;;;;ALrCsC;;;;;AAgB1E;;;;;;;;;;;;iBMUgB,cAAA,WAEV,4BAAA,SAEE,MAAA,sCAIF,sBAAA,SAA+B,MAAA,oCAAA,CACnC,KAAA,EAAO,CAAA,GAAI,kBAAA,CAAmB,CAAA;;;;;;ANnC0C;;;;;AAgB1E;;;;;;;;;;;;;iBOWgB,aAAA,WAEV,4BAAA,SAEE,MAAA,sCAIF,sBAAA,SAA+B,MAAA,oCAAA,CACnC,KAAA,EAAO,CAAA,GAAI,iBAAA,CAAkB,CAAA;;;;;;APpC2C;;;;;AAgB1E;;;;;;;;;;;;;;;;iBQcgB,YAAA,WAEV,4BAAA,SAEE,MAAA,sCAIF,sBAAA,SAA+B,MAAA,oCAAA,CACnC,KAAA,EAAO,CAAA,GAAI,gBAAA,CAAiB,CAAA;;;;;;iBClCd,YAAA,CAAA;;;ATL0D;;;AAAA,iBUW1D,UAAA,CAAA;;AVKhB;;;iBUGgB,YAAA,CAAa,GAAA"}