@real-router/react 0.24.1 → 0.25.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.
Files changed (123) hide show
  1. package/README.md +127 -7
  2. package/dist/cjs/Await-whr-pcvo.d.ts +41 -0
  3. package/dist/cjs/Await-whr-pcvo.d.ts.map +1 -0
  4. package/dist/cjs/HttpStatusProvider-Dh6cMr95.d.ts +143 -0
  5. package/dist/cjs/HttpStatusProvider-Dh6cMr95.d.ts.map +1 -0
  6. package/dist/cjs/Link-BspioC76.js +2 -0
  7. package/dist/cjs/Link-BspioC76.js.map +1 -0
  8. package/dist/cjs/RouterErrorBoundary-BlJmaoyr.d.ts +47 -0
  9. package/dist/cjs/RouterErrorBoundary-BlJmaoyr.d.ts.map +1 -0
  10. package/dist/cjs/{RouterProvider-Bj1_NbpA.d.ts → RouterProvider-DvC9mViF.d.ts} +2 -2
  11. package/dist/cjs/RouterProvider-DvC9mViF.d.ts.map +1 -0
  12. package/dist/cjs/RouterProvider-fJvMO5Tc.js +2 -0
  13. package/dist/cjs/RouterProvider-fJvMO5Tc.js.map +1 -0
  14. package/dist/cjs/createHttpStatusSink-D_6IiR5E.js +2 -0
  15. package/dist/cjs/createHttpStatusSink-D_6IiR5E.js.map +1 -0
  16. package/dist/cjs/index.d.ts +6 -281
  17. package/dist/cjs/index.js +1 -1
  18. package/dist/cjs/index.js.map +1 -1
  19. package/dist/cjs/index.react-server.d.ts +5 -0
  20. package/dist/cjs/index.react-server.js +0 -0
  21. package/dist/cjs/ink.d.ts +2 -1
  22. package/dist/cjs/ink.d.ts.map +1 -1
  23. package/dist/cjs/ink.js +1 -1
  24. package/dist/cjs/ink.js.map +1 -1
  25. package/dist/cjs/legacy.d.ts +3 -2
  26. package/dist/cjs/legacy.js +1 -1
  27. package/dist/cjs/legacy.ssr.d.ts +3 -0
  28. package/dist/cjs/legacy.ssr.js +1 -0
  29. package/dist/cjs/ssr.d.ts +4 -0
  30. package/dist/cjs/ssr.js +2 -0
  31. package/dist/cjs/ssr.js.map +1 -0
  32. package/dist/cjs/ssr.react-server.d.ts +3 -0
  33. package/dist/cjs/ssr.react-server.js +0 -0
  34. package/dist/cjs/useDeferred-DE5YUsfa.d.ts +24 -0
  35. package/dist/cjs/useDeferred-DE5YUsfa.d.ts.map +1 -0
  36. package/dist/cjs/useRoute-Dudo2K_0.js +2 -0
  37. package/dist/cjs/useRoute-Dudo2K_0.js.map +1 -0
  38. package/dist/cjs/useRouteEnter-gfy65W0D.d.ts +279 -0
  39. package/dist/cjs/useRouteEnter-gfy65W0D.d.ts.map +1 -0
  40. package/dist/cjs/useRouterTransition-BfayPs0h.d.ts +56 -0
  41. package/dist/cjs/useRouterTransition-BfayPs0h.d.ts.map +1 -0
  42. package/dist/esm/Await-qSmJ-ZuN.d.mts +41 -0
  43. package/dist/esm/Await-qSmJ-ZuN.d.mts.map +1 -0
  44. package/dist/esm/HttpStatusProvider-Cy9GSANm.d.mts +143 -0
  45. package/dist/esm/HttpStatusProvider-Cy9GSANm.d.mts.map +1 -0
  46. package/dist/esm/Link-BQol2GYb.mjs +2 -0
  47. package/dist/esm/Link-BQol2GYb.mjs.map +1 -0
  48. package/dist/esm/RouterErrorBoundary-C-MH_yrP.d.mts +47 -0
  49. package/dist/esm/RouterErrorBoundary-C-MH_yrP.d.mts.map +1 -0
  50. package/dist/esm/{RouterProvider-Dr3X_vbc.d.mts → RouterProvider-D_ZlPVAC.d.mts} +2 -2
  51. package/dist/esm/RouterProvider-D_ZlPVAC.d.mts.map +1 -0
  52. package/dist/esm/RouterProvider-a9y9bqji.mjs +2 -0
  53. package/dist/esm/RouterProvider-a9y9bqji.mjs.map +1 -0
  54. package/dist/esm/createHttpStatusSink-BXWVamHE.mjs +2 -0
  55. package/dist/esm/createHttpStatusSink-BXWVamHE.mjs.map +1 -0
  56. package/dist/esm/index.d.mts +6 -281
  57. package/dist/esm/index.mjs +1 -1
  58. package/dist/esm/index.mjs.map +1 -1
  59. package/dist/esm/index.react-server.d.mts +5 -0
  60. package/dist/esm/index.react-server.mjs +0 -0
  61. package/dist/esm/ink.d.mts +2 -1
  62. package/dist/esm/ink.d.mts.map +1 -1
  63. package/dist/esm/ink.mjs +1 -1
  64. package/dist/esm/ink.mjs.map +1 -1
  65. package/dist/esm/legacy.d.mts +3 -2
  66. package/dist/esm/legacy.mjs +1 -1
  67. package/dist/esm/legacy.ssr.d.mts +3 -0
  68. package/dist/esm/legacy.ssr.mjs +1 -0
  69. package/dist/esm/ssr.d.mts +4 -0
  70. package/dist/esm/ssr.mjs +2 -0
  71. package/dist/esm/ssr.mjs.map +1 -0
  72. package/dist/esm/ssr.react-server.d.mts +3 -0
  73. package/dist/esm/ssr.react-server.mjs +0 -0
  74. package/dist/esm/useDeferred-B5Qy7ttQ.d.mts +24 -0
  75. package/dist/esm/useDeferred-B5Qy7ttQ.d.mts.map +1 -0
  76. package/dist/esm/useRoute-Bta1jyl2.mjs +2 -0
  77. package/dist/esm/useRoute-Bta1jyl2.mjs.map +1 -0
  78. package/dist/esm/useRouteEnter-CxjYofFa.d.mts +279 -0
  79. package/dist/esm/useRouteEnter-CxjYofFa.d.mts.map +1 -0
  80. package/dist/esm/useRouterTransition-CI1P95ZQ.d.mts +56 -0
  81. package/dist/esm/useRouterTransition-CI1P95ZQ.d.mts.map +1 -0
  82. package/package.json +46 -4
  83. package/src/components/Await.tsx +46 -0
  84. package/src/components/ClientOnly.tsx +25 -0
  85. package/src/components/HttpStatusCode.tsx +66 -0
  86. package/src/components/HttpStatusProvider.tsx +26 -0
  87. package/src/components/InkLink.tsx +44 -22
  88. package/src/components/Link.tsx +32 -36
  89. package/src/components/RouterErrorBoundary.tsx +21 -6
  90. package/src/components/ServerOnly.tsx +26 -0
  91. package/src/components/Streamed.tsx +30 -0
  92. package/src/components/modern/RouteView/RouteView.tsx +9 -3
  93. package/src/components/modern/RouteView/helpers.tsx +26 -16
  94. package/src/constants.ts +7 -8
  95. package/src/context.ts +4 -2
  96. package/src/hooks/useDeferred.tsx +34 -0
  97. package/src/hooks/useIsActiveRoute.tsx +17 -9
  98. package/src/hooks/useNavigator.tsx +0 -2
  99. package/src/hooks/useRoute.tsx +10 -7
  100. package/src/hooks/useRouter.tsx +0 -2
  101. package/src/index.react-server.ts +33 -0
  102. package/src/index.ts +5 -0
  103. package/src/legacy.ssr.ts +35 -0
  104. package/src/legacy.ts +4 -0
  105. package/src/ssr.react-server.ts +21 -0
  106. package/src/ssr.ts +43 -0
  107. package/src/utils/createHttpStatusSink.ts +27 -0
  108. package/dist/cjs/Link-DYvAnJlk.js +0 -2
  109. package/dist/cjs/Link-DYvAnJlk.js.map +0 -1
  110. package/dist/cjs/RouterProvider-Bj1_NbpA.d.ts.map +0 -1
  111. package/dist/cjs/RouterProvider-CfBNR-k7.js +0 -2
  112. package/dist/cjs/RouterProvider-CfBNR-k7.js.map +0 -1
  113. package/dist/cjs/index.d.ts.map +0 -1
  114. package/dist/cjs/useRouterTransition-BYit_9Mt.d.ts +0 -92
  115. package/dist/cjs/useRouterTransition-BYit_9Mt.d.ts.map +0 -1
  116. package/dist/esm/Link-C7upxMc8.mjs +0 -2
  117. package/dist/esm/Link-C7upxMc8.mjs.map +0 -1
  118. package/dist/esm/RouterProvider-CS2ZoONm.mjs +0 -2
  119. package/dist/esm/RouterProvider-CS2ZoONm.mjs.map +0 -1
  120. package/dist/esm/RouterProvider-Dr3X_vbc.d.mts.map +0 -1
  121. package/dist/esm/index.d.mts.map +0 -1
  122. package/dist/esm/useRouterTransition-B65Wvngj.d.mts +0 -92
  123. package/dist/esm/useRouterTransition-B65Wvngj.d.mts.map +0 -1
package/README.md CHANGED
@@ -17,13 +17,18 @@ npm install @real-router/react @real-router/core @real-router/browser-plugin
17
17
 
18
18
  ## Entry Points
19
19
 
20
- | Import Path | React Version | Runtime | Includes |
21
- | --------------------------- | ------------- | ----------------- | ------------------------------------------------------ |
22
- | `@real-router/react` | 19.2+ | DOM | Full API (hooks, `Link`, `RouteView` with `keepAlive`) |
23
- | `@real-router/react/legacy` | 18+ | DOM | All hooks and `Link`, no `RouteView` |
24
- | `@real-router/react/ink` | 19.2+ | Terminal (Ink 7+) | Hooks, `InkRouterProvider`, `InkLink`, no `RouteView` |
20
+ | Import Path | React Version | Runtime | Includes |
21
+ | ---------------------------------- | ------------- | -------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------- |
22
+ | `@real-router/react` | 19.2+ | DOM | Full client API (hooks, `Link`, `RouteView` with `keepAlive`, `RouterErrorBoundary`). **No SSR-feature components** — those live at `/ssr`. |
23
+ | `@real-router/react/ssr` | 19.2+ | DOM (SSR-aware) | `<ClientOnly>`, `<ServerOnly>`, `<Await>`, `<Streamed>`, `useDeferred`, `<HttpStatusCode>`, `<HttpStatusProvider>`, `createHttpStatusSink` |
24
+ | `@real-router/react/legacy` | 18+ | DOM | Client API for React 18 (no `RouteView`, no SSR helpers) |
25
+ | `@real-router/react/legacy/ssr` | 18+ | DOM (SSR-aware) | SSR-feature subset for React 18 — same as `/ssr` minus `<Await>` (which depends on React 19's `use(promise)`) |
26
+ | `@real-router/react/ink` | 19.2+ | Terminal (Ink 7+) | Hooks, `InkRouterProvider`, `InkLink` — no `Link`, no `RouteView`, no `announceNavigation` |
27
+ | `@real-router/react` (`react-server` condition) | 19+ | RSC bundler | **Type-only** re-exports for Server Components — no client runtime. Same condition applies to `/ssr` for prop types. |
25
28
 
26
- All entries share the same underlying hook code. `/legacy` excludes React 19.2 `<Activity>`; `/ink` excludes DOM-bound primitives (`<a>`-based `Link`, `announceNavigation`) and replaces them with keyboard-driven terminal equivalents.
29
+ All client entries share the same underlying hook code. `/legacy` excludes React 19.2 `<Activity>`; `/ink` excludes DOM-bound primitives (`<a>`-based `Link`, `announceNavigation`) and replaces them with keyboard-driven terminal equivalents. The `/ssr` split keeps server-only prop types out of the client TypeScript context for apps that don't touch SSR (bundle cost is ≈ 0 thanks to `"sideEffects": false`).
30
+
31
+ The root export resolves to a **type-only entry** when bundlers apply the `react-server` condition (Vite RSC, Webpack RSC, Turbopack, Parcel) — Server Components can import public API types without pulling client-only code into the server bundle. Per-request data fetching is handled by [@real-router/rsc-server-plugin](https://www.npmjs.com/package/@real-router/rsc-server-plugin), not this entry. See [RSC Integration wiki guide](https://github.com/greydragon888/real-router/wiki/RSC-Integration).
27
32
 
28
33
  ## Quick Start
29
34
 
@@ -202,6 +207,31 @@ const LazyDashboard = lazy(() => import("./Dashboard"));
202
207
 
203
208
  `fallback` and `keepAlive` work together — `<Activity>` wraps the whole match including the `<Suspense>` boundary.
204
209
 
210
+ #### `RouteView.Self`
211
+
212
+ Renders when the active route name **exactly equals** the parent `<RouteView>`'s `nodeName`. Use it for leaf views where the parent route itself is the destination — e.g. `/users` rendering a directory page while `/users/:id` renders inside a nested `<RouteView nodeName="users">`.
213
+
214
+ ```tsx
215
+ <RouteView nodeName="users">
216
+ <RouteView.Self>
217
+ <UsersIndex /> {/* rendered for route name === "users" */}
218
+ </RouteView.Self>
219
+ <RouteView.Match segment="profile">
220
+ <UserProfile /> {/* rendered for "users.profile" and descendants */}
221
+ </RouteView.Match>
222
+ <RouteView.NotFound>
223
+ <NotFoundPage />
224
+ </RouteView.NotFound>
225
+ </RouteView>
226
+ ```
227
+
228
+ | Prop | Type | Description |
229
+ | ---------- | ----------- | -------------------------------------------------------------------------------------------- |
230
+ | `fallback` | `ReactNode` | Symmetric with `RouteView.Match` — wraps `children` in `<Suspense>` when defined. |
231
+ | `children` | `ReactNode` | Content to render when the active route name equals the parent `<RouteView>`'s `nodeName`. |
232
+
233
+ First-wins: if multiple `<RouteView.Self>` elements appear, only the first contributes to the rendered output (same precedence semantics as `<RouteView.NotFound>`). An activating `<RouteView.Match>` suppresses both `Self` and `NotFound`.
234
+
205
235
  ### `<RouterErrorBoundary>`
206
236
 
207
237
  Declarative error handling for navigation errors. Shows a fallback **alongside** children (not instead of) when a guard rejects or a route is not found.
@@ -223,6 +253,94 @@ Auto-resets on next successful navigation. Works with both `<Link>` and imperati
223
253
 
224
254
  Available from both `@real-router/react` and `@real-router/react/legacy`.
225
255
 
256
+ ### `<ClientOnly>` / `<ServerOnly>`
257
+
258
+ Paired SSR-aware boundaries. `<ClientOnly>` renders `fallback` on the server (and on the client first paint, to match SSR HTML), then swaps in `children` after mount. `<ServerOnly>` is the symmetric inverse.
259
+
260
+ ```tsx
261
+ import { ClientOnly, ServerOnly } from "@real-router/react/ssr";
262
+
263
+ <ClientOnly fallback={<Skeleton />}>
264
+ <BrowserApiWidget />
265
+ </ClientOnly>
266
+
267
+ <ServerOnly>
268
+ <SeoMetaStrip />
269
+ </ServerOnly>
270
+ ```
271
+
272
+ Implementation: `useState(false)` + `useEffect(() => setMounted(true), [])`. Server emits the SSR-side branch, client first paint matches it (no hydration mismatch), the post-mount effect triggers a single re-render that swaps the rendered branch.
273
+
274
+ Available from `@real-router/react/ssr` and `@real-router/react/legacy/ssr`. End-to-end dogfooding lives in [`examples/web/react/ssr-examples/ssr/`](../../examples/web/react/ssr-examples/ssr/) (see `e2e/ssr-boundaries.spec.ts`).
275
+
276
+ ### `<Streamed>` / `<Await>` / `useDeferred`
277
+
278
+ Three pieces of the deferred-data pipeline (paired with [`@real-router/ssr-data-plugin`](https://www.npmjs.com/package/@real-router/ssr-data-plugin)'s `defer()` API). `<Streamed>` is a cross-adapter alias for `<Suspense>` so route bundles can use the same boundary name across Solid/Vue/Svelte/React. `<Await<T> name="key">` reads the deferred promise the loader published under that key and hands the resolved value to a render-prop. `useDeferred<T>(key)` returns the same promise for callers that want to compose with `use()` or a third-party suspense library.
279
+
280
+ ```tsx
281
+ import { Streamed, Await, useDeferred } from "@real-router/react/ssr";
282
+
283
+ // Render-prop form — works in React 19.2+ via internal `use(promise)`.
284
+ <Streamed fallback={<Spinner />}>
285
+ <Await<Review[]> name="reviews">
286
+ {(reviews) => <ReviewList items={reviews} />}
287
+ </Await>
288
+ </Streamed>;
289
+
290
+ // Manual form — works on React 18+ (`/legacy/ssr` entry).
291
+ function Reviews() {
292
+ const reviews = use(useDeferred<Review[]>("reviews"));
293
+ return <ReviewList items={reviews} />;
294
+ }
295
+ ```
296
+
297
+ `<Await>` is React 19.2+ only (depends on `use(promise)`); `<Streamed>` and `useDeferred` ship in both `/ssr` and `/legacy/ssr`. End-to-end example: [`examples/web/react/ssr-examples/ssr-streaming/`](../../examples/web/react/ssr-examples/ssr-streaming/).
298
+
299
+ ### `<HttpStatusCode>` / `<HttpStatusProvider>` / `createHttpStatusSink`
300
+
301
+ Render-time HTTP status declaration for SSR responses. Mount `<HttpStatusCode code={N} />` inside a route component (typical use: a `<RouteView.NotFound>` glob page) — it writes `N` to the nearest `<HttpStatusProvider>`'s sink during render and returns `null`. After `renderToString` / `renderToReadableStream`, read `sink.code` and pass it to your response.
302
+
303
+ ```tsx
304
+ // app.tsx
305
+ import { HttpStatusCode } from "@real-router/react/ssr";
306
+
307
+ function NotFound() {
308
+ return (
309
+ <>
310
+ <HttpStatusCode code={404} />
311
+ <h1>Page not found</h1>
312
+ </>
313
+ );
314
+ }
315
+
316
+ // entry-server.tsx
317
+ import { renderToString } from "react-dom/server";
318
+ import {
319
+ HttpStatusProvider,
320
+ createHttpStatusSink,
321
+ } from "@real-router/react/ssr";
322
+
323
+ const sink = createHttpStatusSink();
324
+ const html = renderToString(
325
+ <HttpStatusProvider sink={sink}>
326
+ <RouterProvider router={router}>
327
+ <App />
328
+ </RouterProvider>
329
+ </HttpStatusProvider>,
330
+ );
331
+ response.status(sink.code ?? 200).send(html);
332
+ ```
333
+
334
+ | Export | Kind | Purpose |
335
+ | -------------------------------- | --------- | -------------------------------------------------------------------------------------------------------------------------------------------------------- |
336
+ | `<HttpStatusCode code={N}/>` | component | Writes `code` to the optional context sink during render. Last write wins across multiple instances. No-op without a provider. |
337
+ | `<HttpStatusProvider sink={…}>` | component | Supplies an `HttpStatusSink` to descendant `<HttpStatusCode />` via React context. |
338
+ | `createHttpStatusSink()` | utility | Returns a fresh `{ code: number \| undefined }` sink — construct one per request on the server, read `sink.code` after rendering. |
339
+
340
+ Loader-driven errors (`LoaderNotFound` → 404, `LoaderRedirect` → 30x) keep working as before; this component covers render-time decisions only. **Streaming SSR caveat**: mount `<HttpStatusCode>` in the shell (above every `<Suspense>` that could delay it), or `await stream.allReady` before reading `sink.code` — once the response status flushes, later writes are lost.
341
+
342
+ Available from `@real-router/react/ssr` and `@real-router/react/legacy/ssr`.
343
+
226
344
  ## React 18 Migration
227
345
 
228
346
  One import path change — all hooks and `Link` work identically:
@@ -234,6 +352,8 @@ One import path change — all hooks and `Link` work identically:
234
352
 
235
353
  `RouteView` is not available from `/legacy`. Use `useRouteNode` with a switch/case pattern instead.
236
354
 
355
+ `useRouteExit` and `useRouteEnter` are also not available from `/legacy` — they depend on React 19's concurrent-mode scheduling guarantees. Use `router.subscribeLeave()` directly for exit guards, and `useEffect` for mount-time analytics on React 18.
356
+
237
357
  ## Ink (Terminal UI)
238
358
 
239
359
  `@real-router/react/ink` lets you build terminal apps with the same hooks you use in the browser.
@@ -285,7 +405,7 @@ render(
285
405
  );
286
406
  ```
287
407
 
288
- **Navigation contract:** Tab moves focus between `InkLink`s, Enter calls `router.navigate(...)`. `RouteView` and the DOM `Link` are intentionally absent from this entry — compose routes with `useRouteNode("")` and a switch.
408
+ **Navigation contract:** Tab moves focus between `InkLink`s, Enter calls `router.navigate(...)`. `RouteView` and the DOM `Link` are intentionally absent from this entry — compose routes with `useRouteNode("")` and a switch. `RouterErrorBoundary` is available for terminal error handling.
289
409
 
290
410
  **Install:**
291
411
 
@@ -0,0 +1,41 @@
1
+ import { ReactNode } from "react";
2
+
3
+ //#region src/components/Await.d.ts
4
+ interface AwaitProps<T> {
5
+ /** Deferred key declared in the loader's `defer({ deferred: { <name>: ... } })`. */
6
+ readonly name: string;
7
+ /** Render the resolved value. Suspends while pending; throws inside the
8
+ * nearest Error Boundary on rejection. */
9
+ readonly children: (value: T) => ReactNode;
10
+ }
11
+ /**
12
+ * Ergonomic wrapper around `useDeferred(name)` + React 19's `use(promise)`.
13
+ *
14
+ * ```tsx
15
+ * <Suspense fallback={<Spinner />}>
16
+ * <Await<Review[]> name="reviews">
17
+ * {(reviews) => <ReviewList items={reviews} />}
18
+ * </Await>
19
+ * </Suspense>
20
+ * ```
21
+ *
22
+ * Equivalent to:
23
+ *
24
+ * ```tsx
25
+ * function Inner() {
26
+ * const reviews = use(useDeferred<Review[]>("reviews"));
27
+ * return <ReviewList items={reviews} />;
28
+ * }
29
+ * ```
30
+ *
31
+ * Pick `<Await>` for cross-adapter consistency with the SvelteKit
32
+ * `{#await}` / Solid `<Await/>` shape; pick the inline `use(useDeferred(...))`
33
+ * form if you prefer one fewer abstraction.
34
+ */
35
+ declare function Await<T = unknown>({
36
+ name,
37
+ children
38
+ }: AwaitProps<T>): ReactNode;
39
+ //#endregion
40
+ export { AwaitProps as n, Await as t };
41
+ //# sourceMappingURL=Await-whr-pcvo.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Await-whr-pcvo.d.ts","names":[],"sources":["../../src/components/Await.tsx"],"mappings":";;;UAMiB,UAAA;;WAEN,IAAA;EAFgB;;EAAA,SAKhB,QAAA,GAAW,KAAA,EAAO,CAAA,KAAM,SAAA;AAAA;;;;;;;;AA2BnC;;;;;;;;;;;;;;;;;iBAAgB,KAAA,aAAA,CAAA;EACd,IAAA;EACA;AAAA,GACC,UAAA,CAAW,CAAA,IAAK,SAAA"}
@@ -0,0 +1,143 @@
1
+ import { ReactNode } from "react";
2
+
3
+ //#region src/components/ClientOnly.d.ts
4
+ interface ClientOnlyProps {
5
+ readonly children: ReactNode;
6
+ readonly fallback?: ReactNode;
7
+ }
8
+ declare function ClientOnly({
9
+ children,
10
+ fallback
11
+ }: ClientOnlyProps): ReactNode;
12
+ //#endregion
13
+ //#region src/components/ServerOnly.d.ts
14
+ interface ServerOnlyProps {
15
+ readonly children: ReactNode;
16
+ readonly fallback?: ReactNode;
17
+ }
18
+ declare function ServerOnly({
19
+ children,
20
+ fallback
21
+ }: ServerOnlyProps): ReactNode;
22
+ //#endregion
23
+ //#region src/components/Streamed.d.ts
24
+ interface StreamedProps {
25
+ /** Shown while any descendant `use(promise)` / `<Await>` is pending. */
26
+ readonly fallback: ReactNode;
27
+ readonly children: ReactNode;
28
+ }
29
+ /**
30
+ * Cross-adapter alias for `<Suspense fallback={…}>`. Pairs with `<Await>`
31
+ * for symmetry with `<Streamed>` boundaries in the SvelteKit / Solid
32
+ * deferred-data conventions.
33
+ *
34
+ * ```tsx
35
+ * <Streamed fallback={<Spinner />}>
36
+ * <Await<Review[]> name="reviews">
37
+ * {(reviews) => <ReviewList items={reviews} />}
38
+ * </Await>
39
+ * </Streamed>
40
+ * ```
41
+ *
42
+ * The component is a thin wrapper around React's native `<Suspense>` — no
43
+ * additional behaviour. Use plain `<Suspense>` directly if you don't need
44
+ * the cross-framework naming alignment.
45
+ */
46
+ declare function Streamed({
47
+ fallback,
48
+ children
49
+ }: StreamedProps): ReactNode;
50
+ //#endregion
51
+ //#region src/components/HttpStatusCode.d.ts
52
+ interface HttpStatusCodeProps {
53
+ /** HTTP status to apply to the response. Common values: 404, 410, 451, 503. */
54
+ readonly code: number;
55
+ }
56
+ /**
57
+ * Render-time HTTP status declaration. Mount inside a route component (typical
58
+ * use case: a glob `*` route's NotFound page) when the status is decided by
59
+ * the rendered tree rather than a loader.
60
+ *
61
+ * Writes `code` to the nearest `<HttpStatusProvider>`'s sink during render and
62
+ * returns `null`. With no provider mounted (the standard client-side case)
63
+ * the component is a silent no-op — same component tree hydrates without
64
+ * touching the DOM or warning about mismatches.
65
+ *
66
+ * Loader-driven errors (`LoaderNotFound` → 404, `LoaderRedirect` → 30x) keep
67
+ * working as before; this component covers render-time decisions only.
68
+ *
69
+ * Last write wins when several `<HttpStatusCode />` instances mount in the
70
+ * same render pass — sink reflects the last component that ran.
71
+ *
72
+ * ```tsx
73
+ * // entry-server.tsx
74
+ * import { renderToString } from "react-dom/server";
75
+ * import { createHttpStatusSink, HttpStatusProvider } from "@real-router/react/ssr";
76
+ *
77
+ * const sink = createHttpStatusSink();
78
+ * const html = renderToString(
79
+ * <HttpStatusProvider sink={sink}>
80
+ * <RouterProvider router={router}>
81
+ * <App />
82
+ * </RouterProvider>
83
+ * </HttpStatusProvider>,
84
+ * );
85
+ * response.status(sink.code ?? 200).send(html);
86
+ * ```
87
+ *
88
+ * **Streaming SSR (`renderToReadableStream`):** the response status MUST be
89
+ * sent before the first body byte flushes. If `<HttpStatusCode />` is mounted
90
+ * inside a late-resolving `<Suspense>` boundary, the sink write may happen
91
+ * AFTER the headers are already on the wire — the override is then lost.
92
+ * Either mount the component in the shell (above every `<Suspense>` that
93
+ * could delay it) or `await stream.allReady` before reading `sink.code`
94
+ * (which forfeits streaming benefits). For non-streaming SSR
95
+ * (`renderToString`) there is no such ordering concern.
96
+ *
97
+ * **Valid `code` range:** Node's `res.end()` throws `Invalid status code` on
98
+ * `NaN`, `0`, negative values, or values `> 999` — this surfaces as a 5xx /
99
+ * dropped connection, not silent corruption. Pass a real HTTP status integer
100
+ * (commonly 4xx/5xx; 100-999 is what Node accepts).
101
+ */
102
+ declare function HttpStatusCode({
103
+ code
104
+ }: HttpStatusCodeProps): ReactNode;
105
+ //#endregion
106
+ //#region src/utils/createHttpStatusSink.d.ts
107
+ /**
108
+ * Render-scoped HTTP status sink. Created per request on the server, passed to
109
+ * `<HttpStatusProvider sink={...}>`, and read after `renderToString` /
110
+ * `renderToReadableStream` to apply the value to the HTTP response.
111
+ *
112
+ * Last write wins: if the rendered tree mounts more than one
113
+ * `<HttpStatusCode />`, the value reflects the last component that ran during
114
+ * the render pass.
115
+ *
116
+ * No-op on the client — `<HttpStatusCode />` reads the optional context and
117
+ * skips the write when no provider is mounted, so the same component tree can
118
+ * be hydrated without changing behaviour.
119
+ *
120
+ * Constraints:
121
+ * - **Per-request only.** Don't share a sink across requests; the rendered
122
+ * tree mutates `code` in place. Module-level singletons leak status
123
+ * between concurrent requests.
124
+ * - **Don't `Object.freeze` the sink.** The component writes to `.code`;
125
+ * freezing makes the assignment throw under ESM strict mode.
126
+ */
127
+ interface HttpStatusSink {
128
+ code: number | undefined;
129
+ }
130
+ declare function createHttpStatusSink(): HttpStatusSink;
131
+ //#endregion
132
+ //#region src/components/HttpStatusProvider.d.ts
133
+ interface HttpStatusProviderProps {
134
+ readonly sink: HttpStatusSink;
135
+ readonly children: ReactNode;
136
+ }
137
+ declare function HttpStatusProvider({
138
+ sink,
139
+ children
140
+ }: HttpStatusProviderProps): ReactNode;
141
+ //#endregion
142
+ export { HttpStatusCode as a, StreamedProps as c, ClientOnly as d, ClientOnlyProps as f, createHttpStatusSink as i, ServerOnly as l, HttpStatusProviderProps as n, HttpStatusCodeProps as o, HttpStatusSink as r, Streamed as s, HttpStatusProvider as t, ServerOnlyProps as u };
143
+ //# sourceMappingURL=HttpStatusProvider-Dh6cMr95.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"HttpStatusProvider-Dh6cMr95.d.ts","names":[],"sources":["../../src/components/ClientOnly.tsx","../../src/components/ServerOnly.tsx","../../src/components/Streamed.tsx","../../src/components/HttpStatusCode.tsx","../../src/utils/createHttpStatusSink.ts","../../src/components/HttpStatusProvider.tsx"],"mappings":";;;UAIiB,eAAA;EAAA,SACN,QAAA,EAAU,SAAA;EAAA,SACV,QAAA,GAAW,SAAA;AAAA;AAAA,iBAGN,UAAA,CAAA;EACd,QAAA;EACA;AAAA,GACC,eAAA,GAAkB,SAAA;;;UCRJ,eAAA;EAAA,SACN,QAAA,EAAU,SAAA;EAAA,SACV,QAAA,GAAW,SAAA;AAAA;AAAA,iBAGN,UAAA,CAAA;EACd,QAAA;EACA;AAAA,GACC,eAAA,GAAkB,SAAA;;;UCRJ,aAAA;;WAEN,QAAA,EAAU,SAAA;EAAA,SACV,QAAA,EAAU,SAAA;AAAA;;;;;;;;AFErB;;;;;;;;;;iBEkBgB,QAAA,CAAA;EAAW,QAAA;EAAU;AAAA,GAAY,aAAA,GAAgB,SAAA;;;UCrBhD,mBAAA;;WAEN,IAAA;AAAA;;;;;;;;;AHCX;;;;;;;;;;;;;;;;;;;;ACLA;;;;;;;;;;AAKA;;;;;;;;iBEgDgB,cAAA,CAAA;EAAiB;AAAA,GAAQ,mBAAA,GAAsB,SAAA;;;;;;AHrD/D;;;;;;;;;;AAKA;;;;;;;UIWiB,cAAA;EACf,IAAA;AAAA;AAAA,iBAGc,oBAAA,CAAA,GAAwB,cAAA;;;UCjBvB,uBAAA;EAAA,SACN,IAAA,EAAM,cAAA;EAAA,SACN,QAAA,EAAU,SAAA;AAAA;AAAA,iBAGL,kBAAA,CAAA;EACd,IAAA;EACA;AAAA,GACC,uBAAA,GAA0B,SAAA"}
@@ -0,0 +1,2 @@
1
+ const e=require(`./useRoute-Dudo2K_0.js`),t=require(`./RouterProvider-fJvMO5Tc.js`);let n=require(`react`),r=require(`react/jsx-runtime`);function i(e,n){return e.routeName===n.routeName&&e.className===n.className&&e.activeClassName===n.activeClassName&&e.activeStrict===n.activeStrict&&e.ignoreQueryParams===n.ignoreQueryParams&&e.onClick===n.onClick&&e.target===n.target&&e.style===n.style&&e.children===n.children&&e.hash===n.hash&&t.u(e.routeParams,n.routeParams)&&t.u(e.routeOptions,n.routeOptions)}const a=(0,n.memo)(({routeName:i,routeParams:a=e.r,routeOptions:o=e.n,className:s,activeClassName:c=`active`,activeStrict:l=!1,ignoreQueryParams:u=!0,hash:d,onClick:f,target:p,children:m,...h})=>{let g=t.p(),_=t.o(i,a,l,u,d),v=t.c(g,i,a,d===void 0?void 0:{hash:d}),y=e=>{f&&(f(e),e.defaultPrevented)||!t.d(e.nativeEvent)||p===`_blank`||(e.preventDefault(),t.l(g,i,a,d,o).catch(()=>{}))},b=(0,n.useMemo)(()=>t.s(_,c,s),[_,c,s]);return(0,r.jsx)(`a`,{...h,href:v,className:b,onClick:y,children:m})},i);a.displayName=`Link`,Object.defineProperty(exports,`t`,{enumerable:!0,get:function(){return a}});
2
+ //# sourceMappingURL=Link-BspioC76.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Link-BspioC76.js","names":["shallowEqual","EMPTY_PARAMS","EMPTY_OPTIONS","useRouter","useIsActiveRoute","buildHref","shouldNavigate","buildActiveClassName"],"sources":["../../src/components/Link.tsx"],"sourcesContent":["import { memo, useMemo } from \"react\";\n\nimport { EMPTY_PARAMS, EMPTY_OPTIONS } from \"../constants\";\nimport {\n shouldNavigate,\n buildHref,\n buildActiveClassName,\n navigateWithHash,\n shallowEqual,\n} from \"../dom-utils\";\nimport { useIsActiveRoute } from \"../hooks/useIsActiveRoute\";\nimport { useRouter } from \"../hooks/useRouter\";\n\nimport type { LinkProps } from \"../types\";\nimport type { FC, MouseEvent } from \"react\";\n\nfunction areLinkPropsEqual(\n prev: Readonly<LinkProps>,\n next: Readonly<LinkProps>,\n): boolean {\n return (\n prev.routeName === next.routeName &&\n prev.className === next.className &&\n prev.activeClassName === next.activeClassName &&\n prev.activeStrict === next.activeStrict &&\n prev.ignoreQueryParams === next.ignoreQueryParams &&\n prev.onClick === next.onClick &&\n prev.target === next.target &&\n prev.style === next.style &&\n prev.children === next.children &&\n prev.hash === next.hash &&\n shallowEqual(prev.routeParams, next.routeParams) &&\n shallowEqual(prev.routeOptions, next.routeOptions)\n );\n}\n\nconst LinkImpl: FC<LinkProps> = ({\n routeName,\n routeParams = EMPTY_PARAMS,\n routeOptions = EMPTY_OPTIONS,\n className,\n activeClassName = \"active\",\n activeStrict = false,\n ignoreQueryParams = true,\n hash,\n onClick,\n target,\n children,\n ...props\n}) => {\n // memo + areLinkPropsEqual guarantees that on bail-out the component does\n // not render; on render, routeParams/routeOptions either changed reference\n // (true change) or comparator failed (e.g., BigInt fallback to identity),\n // so they're safe to use directly in hook deps.\n\n const router = useRouter();\n\n // When `hash` prop is set, active state requires both route AND hash to\n // match (#532). Without this, three tab links sharing routeName=\"settings\"\n // would all be marked active by route-name alone, defeating tab semantics.\n const isActive = useIsActiveRoute(\n routeName,\n routeParams,\n activeStrict,\n ignoreQueryParams,\n hash,\n );\n\n // No useMemo: outer memo()+shallowEqual prevents Link re-render unless a\n // prop actually changed. When this body runs, either `hash` differs from\n // last render or another prop changed — in both cases the `{ hash }` alloc\n // is unavoidable. The useMemo wrapper added one closure + deps slot per\n // render without saving an allocation.\n const hashOption = hash === undefined ? undefined : { hash };\n const href = buildHref(router, routeName, routeParams, hashOption);\n\n // useCallback was wasteful: 7 deps recreated the closure on every meaningful\n // render anyway, and `<a onClick>` does not benefit from a stable function\n // identity (no child-memo-bail-out chain past it). Inline arrow function is\n // what React Compiler emits automatically for this shape.\n const handleClick = (evt: MouseEvent<HTMLAnchorElement>) => {\n if (onClick) {\n onClick(evt);\n\n if (evt.defaultPrevented) {\n return;\n }\n }\n\n if (!shouldNavigate(evt.nativeEvent) || target === \"_blank\") {\n return;\n }\n\n evt.preventDefault();\n navigateWithHash(router, routeName, routeParams, hash, routeOptions).catch(\n () => {},\n );\n };\n\n // Memoize the joined class string. parseTokens + Set + join on every render\n // adds up on pages with N Links navigating frequently; deps cover every\n // input the function reads so cache invalidation is exact.\n const finalClassName = useMemo(\n () => buildActiveClassName(isActive, activeClassName, className),\n [isActive, activeClassName, className],\n );\n\n return (\n <a {...props} href={href} className={finalClassName} onClick={handleClick}>\n {children}\n </a>\n );\n};\n\nexport const Link: FC<LinkProps> = memo(LinkImpl, areLinkPropsEqual);\n\nLink.displayName = \"Link\";\n"],"mappings":"0IAgBA,SAAS,EACP,EACA,EACS,CACT,OACE,EAAK,YAAc,EAAK,WACxB,EAAK,YAAc,EAAK,WACxB,EAAK,kBAAoB,EAAK,iBAC9B,EAAK,eAAiB,EAAK,cAC3B,EAAK,oBAAsB,EAAK,mBAChC,EAAK,UAAY,EAAK,SACtB,EAAK,SAAW,EAAK,QACrB,EAAK,QAAU,EAAK,OACpB,EAAK,WAAa,EAAK,UACvB,EAAK,OAAS,EAAK,MACnBA,EAAAA,EAAa,EAAK,YAAa,EAAK,YAAY,EAChDA,EAAAA,EAAa,EAAK,aAAc,EAAK,aAAa,CAkFtD,MAAa,GAAA,EAAA,EAAA,OA9EoB,CAC/B,YACA,cAAcC,EAAAA,EACd,eAAeC,EAAAA,EACf,YACA,kBAAkB,SAClB,eAAe,GACf,oBAAoB,GACpB,OACA,UACA,SACA,WACA,GAAG,KACC,CAMJ,IAAM,EAASC,EAAAA,GAAW,CAKpB,EAAWC,EAAAA,EACf,EACA,EACA,EACA,EACA,EACD,CAQK,EAAOC,EAAAA,EAAU,EAAQ,EAAW,EADvB,IAAS,IAAA,GAAY,IAAA,GAAY,CAAE,OAAM,CACM,CAM5D,EAAe,GAAuC,CACtD,IACF,EAAQ,EAAI,CAER,EAAI,mBAKN,CAACC,EAAAA,EAAe,EAAI,YAAY,EAAI,IAAW,WAInD,EAAI,gBAAgB,CACpB,EAAA,EAAiB,EAAQ,EAAW,EAAa,EAAM,EAAa,CAAC,UAC7D,GACP,GAMG,GAAA,EAAA,EAAA,aACEC,EAAAA,EAAqB,EAAU,EAAiB,EAAU,CAChE,CAAC,EAAU,EAAiB,EAAU,CACvC,CAED,OACE,EAAA,EAAA,KAAC,IAAD,CAAG,GAAI,EAAa,OAAM,UAAW,EAAgB,QAAS,EAC3D,WACC,CAAA,EAI0C,EAAkB,CAEpE,EAAK,YAAc"}
@@ -0,0 +1,47 @@
1
+ import { HTMLAttributes, MouseEventHandler, ReactElement, ReactNode } from "react";
2
+ import { NavigationOptions, Navigator, Params, RouterError, State } from "@real-router/core";
3
+
4
+ //#region src/types.d.ts
5
+ interface RouteState<P extends Params = Params> {
6
+ route: State<P> | undefined;
7
+ previousRoute?: State | undefined;
8
+ }
9
+ type RouteContext<P extends Params = Params> = {
10
+ navigator: Navigator;
11
+ } & RouteState<P>;
12
+ interface LinkProps<P extends Params = Params> extends HTMLAttributes<HTMLAnchorElement> {
13
+ routeName: string;
14
+ routeParams?: P;
15
+ routeOptions?: NavigationOptions;
16
+ activeClassName?: string;
17
+ activeStrict?: boolean;
18
+ ignoreQueryParams?: boolean;
19
+ /**
20
+ * URL fragment (decoded form, no leading "#") (#532).
21
+ * - omitted/`undefined` → preserve current fragment on same-route navigation
22
+ * - `""` → clear fragment
23
+ * - non-empty → set fragment
24
+ *
25
+ * Requires a URL plugin (browser-plugin or navigation-plugin) for full
26
+ * round-trip; hash-plugin ignores the prop with a one-time dev warning.
27
+ */
28
+ hash?: string;
29
+ target?: string;
30
+ onClick?: MouseEventHandler<HTMLAnchorElement>;
31
+ onMouseOver?: MouseEventHandler<HTMLAnchorElement>;
32
+ }
33
+ //#endregion
34
+ //#region src/components/RouterErrorBoundary.d.ts
35
+ interface RouterErrorBoundaryProps {
36
+ readonly children: ReactNode;
37
+ readonly fallback: (error: RouterError, resetError: () => void) => ReactNode;
38
+ readonly onError?: (error: RouterError, toRoute: State | null, fromRoute: State | null) => void;
39
+ }
40
+ declare function RouterErrorBoundary({
41
+ children,
42
+ fallback,
43
+ onError
44
+ }: RouterErrorBoundaryProps): ReactElement;
45
+ //#endregion
46
+ export { RouteContext as i, RouterErrorBoundaryProps as n, LinkProps as r, RouterErrorBoundary as t };
47
+ //# sourceMappingURL=RouterErrorBoundary-BlJmaoyr.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"RouterErrorBoundary-BlJmaoyr.d.ts","names":[],"sources":["../../src/types.ts","../../src/components/RouterErrorBoundary.tsx"],"mappings":";;;;UAQiB,UAAA,WAAqB,MAAA,GAAS,MAAA;EAC7C,KAAA,EAAO,KAAA,CAAM,CAAA;EACb,aAAA,GAAgB,KAAA;AAAA;AAAA,KAGN,YAAA,WAAuB,MAAA,GAAS,MAAA;EAC1C,SAAA,EAAW,SAAA;AAAA,IACT,UAAA,CAAW,CAAA;AAAA,UAEE,SAAA,WACL,MAAA,GAAS,MAAA,UACX,cAAA,CAAe,iBAAA;EACvB,SAAA;EACA,WAAA,GAAc,CAAA;EACd,YAAA,GAAe,iBAAA;EACf,eAAA;EACA,YAAA;EACA,iBAAA;EAjB6C;;;;;;;;AAK/C;EAsBE,IAAA;EACA,MAAA;EACA,OAAA,GAAU,iBAAA,CAAkB,iBAAA;EAC5B,WAAA,GAAc,iBAAA,CAAkB,iBAAA;AAAA;;;UCxBjB,wBAAA;EAAA,SACN,QAAA,EAAU,SAAA;EAAA,SACV,QAAA,GAAW,KAAA,EAAO,WAAA,EAAa,UAAA,iBAA2B,SAAA;EAAA,SAC1D,OAAA,IACP,KAAA,EAAO,WAAA,EACP,OAAA,EAAS,KAAA,SACT,SAAA,EAAW,KAAA;AAAA;AAAA,iBAIC,mBAAA,CAAA;EACd,QAAA;EACA,QAAA;EACA;AAAA,GACC,wBAAA,GAA2B,YAAA"}
@@ -1,4 +1,4 @@
1
- import { l as LinkProps } from "./useRouterTransition-BYit_9Mt.js";
1
+ import { r as LinkProps } from "./RouterErrorBoundary-BlJmaoyr.js";
2
2
  import { FC, ReactNode } from "react";
3
3
  import { NavigationOptions, Params, Router, State } from "@real-router/core";
4
4
 
@@ -45,4 +45,4 @@ interface RouteProviderProps {
45
45
  declare const RouterProvider: FC<RouteProviderProps>;
46
46
  //#endregion
47
47
  export { Link as n, RouterProvider as t };
48
- //# sourceMappingURL=RouterProvider-Bj1_NbpA.d.ts.map
48
+ //# sourceMappingURL=RouterProvider-DvC9mViF.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"RouterProvider-DvC9mViF.d.ts","names":[],"sources":["../../src/components/Link.tsx","../../../../shared/dom-utils/scroll-restore.ts","../../src/RouterProvider.tsx"],"mappings":";;;;;cAkHa,IAAA,EAAM,EAAA,CAAG,SAAA;;;KCxGV,qBAAA;AAAA,UAEK,wBAAA;EACf,IAAA,GAAO,qBAAA;EACP,eAAA;EACA,eAAA,UAAyB,WAAA;EDmGyC;;;;;;;ACxGpE;;;;;EAkBE,QAAA,GAAW,cAAA;EAhB4B;;;;;;;EAwBvC,UAAA;AAAA;;;UCrBe,kBAAA;EACf,MAAA,EAAQ,MAAA;EACR,QAAA,EAAU,SAAA;EACV,kBAAA;EACA,iBAAA,GAAoB,wBAAA;EACpB,eAAA;AAAA;AAAA,cAGW,cAAA,EAAgB,EAAA,CAAG,kBAAA"}
@@ -0,0 +1,2 @@
1
+ const e=require(`./useRoute-Dudo2K_0.js`);let t=require(`react`),n=require(`@real-router/core`),r=require(`@real-router/route-utils`),i=require(`react/jsx-runtime`),a=require(`@real-router/sources`),o=require(`@real-router/core/api`);const s=()=>{let n=(0,t.useContext)(e.s);if(!n)throw Error(`useRouter must be used within a RouterProvider`);return n};function c(e){let r=s(),i=(0,t.useMemo)(()=>(0,a.createRouteNodeSource)(r,e),[r,e]),o=(0,t.useSyncExternalStore)(i.subscribe,i.getSnapshot,i.getSnapshot),c=(0,n.getNavigator)(r);return(0,t.useMemo)(()=>({navigator:c,route:o.route,previousRoute:o.previousRoute}),[c,o])}const l=`data-real-router-announcer`,u=Object.freeze({destroy:()=>{}});function d(e,t){if(typeof document>`u`)return u;let n=t?.prefix??`Navigated to `,r=t?.getAnnouncementText,i=!0,a=!1,o=!1,s=``,c=null,l,d=f(),g=(e,t)=>{s=e,clearTimeout(l),d.textContent=e,l=setTimeout(()=>{d.textContent=``,s=``},7e3),h(t)},_=setTimeout(()=>{if(a=!0,c!==null&&!o){let e=c;c=null,g(e,document.querySelector(`h1`))}},100),v=e.subscribe(({route:e})=>{if(i){i=!1;return}requestAnimationFrame(()=>{requestAnimationFrame(()=>{if(o)return;let t=document.querySelector(`h1`),i=m(e,n,r,t);if(!(!i||i===s)){if(!a){c=i;return}g(i,t)}})})});return{destroy(){o=!0,v(),clearTimeout(l),clearTimeout(_),p()}}}function f(){let e=document.querySelector(`[${l}]`);if(e)return e;let t=document.createElement(`div`);return t.setAttribute(`style`,`position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);clip-path:inset(50%);white-space:nowrap;border:0`),t.setAttribute(`aria-live`,`assertive`),t.setAttribute(`aria-atomic`,`true`),t.setAttribute(l,``),(document.body??document.documentElement).prepend(t),t}function p(){document.querySelector(`[${l}]`)?.remove()}function m(e,t,n,r){if(n)try{let t=n(e);if(t)return t}catch(e){console.error(`[real-router] getAnnouncementText threw; falling back to default resolution.`,e)}let i=(r?.textContent??``).trim(),a=e.name.startsWith(`@@`)?``:e.name;return`${t}${i||document.title||a||globalThis.location.pathname}`}function h(e){e&&(e.hasAttribute(`tabindex`)||e.setAttribute(`tabindex`,`-1`),e.focus({preventScroll:!0}))}const g=Object.freeze({destroy:()=>{}});function _(e,t){if(globalThis.window===void 0)return g;let n=t?.mode??`restore`;if(n===`native`)return g;let r=t?.anchorScrolling??!0,i=t?.scrollContainer,a=t?.behavior??`auto`,o=t?.storageKey??`real-router:scroll`,s,c=()=>{if(s!==void 0)return s;try{let e=sessionStorage.getItem(o);s=e?JSON.parse(e):{}}catch{s={}}return s},l=(e,t)=>{try{let n=c();if(n[e]===t)return;n[e]=t,sessionStorage.setItem(o,JSON.stringify(n))}catch{}},u=history.scrollRestoration;try{history.scrollRestoration=`manual`}catch{}let d=()=>{let e=i?.();return e?e.scrollTop:globalThis.scrollY},f=e=>{let t=i?.();t?t.scrollTo({top:e,left:0,behavior:a}):globalThis.scrollTo({top:e,left:0,behavior:a})},p=e=>{let t=e.context?.url?.hash;if(t!==void 0){if(r&&t.length>0){let e=document.getElementById(t);if(e){e.scrollIntoView({behavior:a});return}}f(0);return}let n=globalThis.location.hash;if(r&&n.length>1){let e;try{e=decodeURIComponent(n.slice(1))}catch{e=n.slice(1)}let t=document.getElementById(e);if(t){t.scrollIntoView({behavior:a});return}}f(0)},m=!1,h=!1,_=e=>{try{return y(e)}catch{return h||(h=!0,console.error(`[real-router] scroll-restore: route "${e.name}" has params that cannot be canonicalized (e.g. BigInt or cyclic structure). Scroll position will not be captured or restored for this route.`)),null}},v=e.subscribe(({route:e,previousRoute:t})=>{let r=e.context.navigation;if(t){let e=_(t);e!==null&&l(e,d())}requestAnimationFrame(()=>{if(!m){if(n===`top`||!r){p(e);return}if(r.navigationType!==`replace`){if(r.direction===`back`||r.navigationType===`traverse`||r.navigationType===`reload`){let t=_(e);f(t===null?0:c()[t]??0);return}p(e)}}})}),b=()=>{let t=e.getState();if(t){let e=_(t);e!==null&&l(e,d())}};return globalThis.addEventListener(`pagehide`,b),{destroy:()=>{if(!m){m=!0,v(),globalThis.removeEventListener(`pagehide`,b);try{history.scrollRestoration=u}catch{}}}}}const v=new WeakMap;function y(e){let t=v.get(e);if(t!==void 0)return t;let n=`${e.name}:${b(e.params)}`;return v.set(e,n),n}function b(e){return JSON.stringify(e,x)}function x(e,t){if(typeof t==`function`)return`<fn>`;if(typeof t==`symbol`)return`<sym>`;if(typeof t==`object`&&t&&!Array.isArray(t)){let e=Object.create(null),n=Object.keys(t).sort((e,t)=>e.localeCompare(t));for(let r of n)e[r]=t[r];return e}return t}const S=Object.freeze({destroy:()=>{}});function C(e){if(typeof document>`u`||typeof document.startViewTransition!=`function`)return S;let t=null,n=null,r=!1,i=()=>{t?.(),t=null},a=e.subscribeLeave(({signal:e})=>{if(!e.aborted)return r=!1,i(),new Promise(a=>{let o=new Promise(e=>{t=e});e.addEventListener(`abort`,()=>{r||(i(),n?.skipTransition?.(),a())},{once:!0});try{n=document.startViewTransition(()=>(a(),o))}catch{i(),a()}})}),o=e.subscribe(()=>{let e=t;r=!0,t=null,e===null?n=null:setTimeout(()=>{e(),n=null},0)});return{destroy:()=>{a(),o(),n?.skipTransition?.(),n=null,i()}}}function w(e){return e.button===0&&!e.metaKey&&!e.altKey&&!e.ctrlKey&&!e.shiftKey}const T=/%[\dA-Fa-f]{2}/;function E(e){if(T.test(e))try{return encodeURI(decodeURIComponent(e)).replaceAll(`#`,`%23`)}catch{}return encodeURI(e).replaceAll(`#`,`%23`)}function D(e,t,n,r){try{let i=r?.hash,a;i!==void 0&&(a=i.startsWith(`#`)?i.slice(1):i);let o=e.buildUrl;if(o){let e=o(t,n,a===void 0?void 0:{hash:a});if(typeof e==`string`&&e.length>0)return e}let s=e.buildPath(t,n);if(typeof s!=`string`||s.length===0){console.error(`[real-router] Route "${t}" yielded an empty path. The element will render without an href attribute.`);return}return a?`${s}#${E(a)}`:s}catch{console.error(`[real-router] Route "${t}" is not defined. The element will render without an href attribute.`);return}}function O(e,t,n,r,i){let a={...i};r!==void 0&&(a.hash=r);let o=e.getState();if(o?.name===t&&N(o.params,n)){let e=o.context?.url?.hash??``;e!==(r??e)&&(a.force=!0,a.hashChange=!0)}return e.navigate(t,n,a)}const k=/\s/,A=/\S+/g;function j(e){return e?k.test(e)?e.match(A)??[]:[e]:[]}function M(e,t,n){if(e&&t){let e=j(t);if(e.length===0)return n??void 0;if(!n)return e.join(` `);let r=j(n),i=new Set(r);for(let t of e)i.has(t)||(i.add(t),r.push(t));return r.join(` `)}return n??void 0}function N(e,t){if(Object.is(e,t))return!0;if(!e||!t)return!1;let n=Object.keys(e);if(n.length!==Object.keys(t).length)return!1;let r=e,i=t;for(let e of n)if(!Object.prototype.hasOwnProperty.call(t,e)||!Object.is(r[e],i[e]))return!1;return!0}function P(e,n,r=!1,i=!0,o){let c=s(),l=(0,t.useMemo)(()=>(0,a.createActiveRouteSource)(c,e,n,{strict:r,ignoreQueryParams:i,...o!==void 0&&{hash:o}}),[c,e,n,r,i,o]);return(0,t.useSyncExternalStore)(l.subscribe,l.getSnapshot,l.getSnapshot)}function F({children:e,fallback:n,onError:r}){let o=s(),c=(0,t.useMemo)(()=>(0,a.createDismissableError)(o),[o]),l=(0,t.useSyncExternalStore)(c.subscribe,c.getSnapshot,c.getSnapshot),u=(0,t.useRef)(r);return(0,t.useLayoutEffect)(()=>{u.current=r}),(0,t.useEffect)(()=>{l.error&&u.current?.(l.error,l.toRoute,l.fromRoute)},[l.version]),(0,i.jsxs)(i.Fragment,{children:[e,l.error?n(l.error,l.resetError):null]})}const I=()=>{let n=(0,t.useContext)(e.a);if(!n)throw Error(`useNavigator must be used within a RouterProvider`);return n},L=()=>(0,r.getRouteUtils)((0,o.getPluginApi)(s()).getTree());function R(){let e=(0,a.getTransitionSource)(s());return(0,t.useSyncExternalStore)(e.subscribe,e.getSnapshot,e.getSnapshot)}const z=({router:r,children:o,announceNavigation:s,scrollRestoration:c,viewTransitions:l})=>{(0,t.useEffect)(()=>{if(!s)return;let e=d(r);return()=>{e.destroy()}},[s,r]);let u=c?.mode,f=c?.anchorScrolling,p=c?.behavior,m=c?.storageKey,h=c!==void 0;(0,t.useEffect)(()=>{if(!h)return;let e=_(r,{mode:u,anchorScrolling:f,behavior:p,storageKey:m,scrollContainer:c.scrollContainer});return()=>{e.destroy()}},[r,h,u,f,p,m]),(0,t.useEffect)(()=>{if(!l)return;let e=C(r);return()=>{e.destroy()}},[r,l]);let g=(0,t.useMemo)(()=>(0,n.getNavigator)(r),[r]),v=(0,t.useMemo)(()=>(0,a.createRouteSource)(r),[r]),y=(0,t.useSyncExternalStore)(v.subscribe,v.getSnapshot,v.getSnapshot),b=(0,t.useMemo)(()=>({navigator:g,route:y.route,previousRoute:y.previousRoute}),[g,y]);return(0,i.jsx)(e.s.Provider,{value:r,children:(0,i.jsx)(e.a.Provider,{value:g,children:(0,i.jsx)(e.o.Provider,{value:b,children:o})})})};Object.defineProperty(exports,`a`,{enumerable:!0,get:function(){return F}}),Object.defineProperty(exports,`c`,{enumerable:!0,get:function(){return D}}),Object.defineProperty(exports,`d`,{enumerable:!0,get:function(){return w}}),Object.defineProperty(exports,`f`,{enumerable:!0,get:function(){return c}}),Object.defineProperty(exports,`i`,{enumerable:!0,get:function(){return I}}),Object.defineProperty(exports,`l`,{enumerable:!0,get:function(){return O}}),Object.defineProperty(exports,`n`,{enumerable:!0,get:function(){return R}}),Object.defineProperty(exports,`o`,{enumerable:!0,get:function(){return P}}),Object.defineProperty(exports,`p`,{enumerable:!0,get:function(){return s}}),Object.defineProperty(exports,`r`,{enumerable:!0,get:function(){return L}}),Object.defineProperty(exports,`s`,{enumerable:!0,get:function(){return M}}),Object.defineProperty(exports,`t`,{enumerable:!0,get:function(){return z}}),Object.defineProperty(exports,`u`,{enumerable:!0,get:function(){return N}});
2
+ //# sourceMappingURL=RouterProvider-fJvMO5Tc.js.map