@real-router/preact 0.15.1 → 0.15.2

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.
@@ -1 +1 @@
1
- {"version":3,"file":"ssr.d.ts","names":[],"sources":["../../src/components/ClientOnly.tsx","../../src/components/ServerOnly.tsx","../../src/components/Await.tsx","../../src/components/Streamed.tsx","../../src/components/HttpStatusCode.tsx","../../src/utils/createHttpStatusSink.ts","../../src/components/HttpStatusProvider.tsx","../../src/hooks/useDeferred.tsx"],"mappings":";;;UAIiB,eAAA;EAAA,SACN,QAAA,EAAU,iBAAA;EAAA,SACV,QAAA,GAAW,iBAAiB;AAAA;AAAA,iBAGvB,UAAA,CAAA;EACd,QAAA;EACA;AAAA,GACC,eAAA,GAAkB,iBAAA;;;UCRJ,eAAA;EAAA,SACN,QAAA,EAAU,iBAAA;EAAA,SACV,QAAA,GAAW,iBAAiB;AAAA;AAAA,iBAGvB,UAAA,CAAA;EACd,QAAA;EACA;AAAA,GACC,eAAA,GAAkB,iBAAA;;;UC6CJ,UAAA;;WAEN,IAAA;EFvDqB;;EAAA,SE0DrB,QAAA,GAAW,KAAA,EAAO,CAAA,KAAM,iBAAiB;AAAA;;;;;AFxDb;AAGvC;;;;;;;;iBEqEgB,KAAA,aAAA,CAAA;EACd,IAAA;EACA;AAAA,GACC,UAAA,CAAW,CAAA,IAAK,iBAAA;;;UC7EF,aAAA;;WAEN,QAAA,EAAU,iBAAA;EAAA,SACV,QAAA,EAAU,iBAAiB;AAAA;;;;;;;AHDC;AAGvC;iBGSgB,QAAA,CAAA;EACd,QAAA;EACA;AAAA,GACC,aAAA,GAAgB,iBAAA;;;UCfF,mBAAA;;WAEN,IAAI;AAAA;;;;;;;;AJFwB;AAGvC;;;;;;;;;;;;;;;;AAGsC;;;;ACRtC;;;;;;;;;AAEuC;AAGvC;;;;;;;iBG+CgB,cAAA,CAAA;EACd;AAAA,GACC,mBAAA,GAAsB,iBAAA;;;;;;AJtDzB;;;;;;;;;AAEuC;AAGvC;;;;;;;UKWiB,cAAA;EACf,IAAI;AAAA;AAAA,iBAGU,oBAAA,CAAA,GAAwB,cAAc;;;UCjBrC,uBAAA;EAAA,SACN,IAAA,EAAM,cAAA;EAAA,SACN,QAAA,EAAU,iBAAiB;AAAA;AAAA,iBAGtB,kBAAA,CAAA;EACd,IAAA;EACA;AAAA,GACC,uBAAA,GAA0B,iBAAA;;;;;;ANX7B;;;;iBOcgB,WAAA,aAAA,CAAyB,GAAA,WAAc,OAAO,CAAC,CAAA"}
1
+ {"version":3,"file":"ssr.d.ts","names":[],"sources":["../../src/components/ClientOnly.tsx","../../src/components/ServerOnly.tsx","../../src/components/Await.tsx","../../src/components/Streamed.tsx","../../src/components/HttpStatusCode.tsx","../../src/utils/createHttpStatusSink.ts","../../src/components/HttpStatusProvider.tsx","../../src/hooks/useDeferred.tsx"],"mappings":";;;UAIiB,eAAA;EAAA,SACN,QAAA,EAAU,iBAAA;EAAA,SACV,QAAA,GAAW,iBAAiB;AAAA;AAAA,iBAGvB,UAAA;EACd,QAAA;EACA;AAAA,GACC,eAAA,GAAkB,iBAAA;;;UCRJ,eAAA;EAAA,SACN,QAAA,EAAU,iBAAA;EAAA,SACV,QAAA,GAAW,iBAAiB;AAAA;AAAA,iBAGvB,UAAA;EACd,QAAA;EACA;AAAA,GACC,eAAA,GAAkB,iBAAA;;;UC6CJ,UAAA;;WAEN,IAAA;EFvDqB;;EAAA,SE0DrB,QAAA,GAAW,KAAA,EAAO,CAAA,KAAM,iBAAiB;AAAA;;;;;AFxDb;AAGvC;;;;;;;;iBEqEgB,KAAA;EACd,IAAA;EACA;AAAA,GACC,UAAA,CAAW,CAAA,IAAK,iBAAA;;;UC7EF,aAAA;;WAEN,QAAA,EAAU,iBAAA;EAAA,SACV,QAAA,EAAU,iBAAiB;AAAA;;;;;;;AHDC;AAGvC;iBGSgB,QAAA;EACd,QAAA;EACA;AAAA,GACC,aAAA,GAAgB,iBAAA;;;UCfF,mBAAA;;WAEN,IAAI;AAAA;;;;;;;;AJFwB;AAGvC;;;;;;;;;;;;;;;;AAGsC;;;;ACRtC;;;;;;;;;AAEuC;AAGvC;;;;;;;iBG+CgB,cAAA;EACd;AAAA,GACC,mBAAA,GAAsB,iBAAA;;;;;;AJtDzB;;;;;;;;;AAEuC;AAGvC;;;;;;;UKWiB,cAAA;EACf,IAAI;AAAA;AAAA,iBAGU,oBAAA,IAAwB,cAAc;;;UCjBrC,uBAAA;EAAA,SACN,IAAA,EAAM,cAAA;EAAA,SACN,QAAA,EAAU,iBAAiB;AAAA;AAAA,iBAGtB,kBAAA;EACd,IAAA;EACA;AAAA,GACC,uBAAA,GAA0B,iBAAA;;;;;;ANX7B;;;;iBOcgB,WAAA,cAAyB,GAAA,WAAc,OAAO,CAAC,CAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"ssr.js","names":["useRoute","Suspense"],"sources":["../../src/components/ClientOnly.tsx","../../src/components/ServerOnly.tsx","../../src/hooks/useDeferred.tsx","../../src/components/Await.tsx","../../src/components/Streamed.tsx","../../src/components/HttpStatusProvider.tsx","../../src/components/HttpStatusCode.tsx","../../src/utils/createHttpStatusSink.ts"],"sourcesContent":["import { useEffect, useState } from \"preact/hooks\";\n\nimport type { ComponentChildren } from \"preact\";\n\nexport interface ClientOnlyProps {\n readonly children: ComponentChildren;\n readonly fallback?: ComponentChildren;\n}\n\nexport function ClientOnly({\n children,\n fallback = null,\n}: ClientOnlyProps): ComponentChildren {\n const [mounted, setMounted] = useState(false);\n\n useEffect(() => {\n // SSR/hydration boundary: server emits the fallback branch, client matches\n // it on first paint, then this effect flips state to swap in the children.\n // The intentional re-render is what makes the markup match across renders.\n // eslint-disable-next-line @eslint-react/set-state-in-effect -- intentional post-hydration swap\n setMounted(true);\n }, []);\n\n return mounted ? children : fallback;\n}\n","import { useEffect, useState } from \"preact/hooks\";\n\nimport type { ComponentChildren } from \"preact\";\n\nexport interface ServerOnlyProps {\n readonly children: ComponentChildren;\n readonly fallback?: ComponentChildren;\n}\n\nexport function ServerOnly({\n children,\n fallback = null,\n}: ServerOnlyProps): ComponentChildren {\n const [mounted, setMounted] = useState(false);\n\n useEffect(() => {\n // SSR/hydration boundary: server emits the children branch, client matches\n // it on first paint, then this effect flips state to swap in the fallback\n // (or hide entirely). The intentional re-render keeps markup consistent\n // across renders.\n // eslint-disable-next-line @eslint-react/set-state-in-effect -- intentional post-hydration swap\n setMounted(true);\n }, []);\n\n return mounted ? fallback : children;\n}\n","import { useRoute } from \"./useRoute\";\n\ninterface DeferredContext {\n ssrDataDeferred?: Record<string, Promise<unknown>>;\n}\n\nconst NEVER_PROMISE = new Promise<never>(() => {\n // Intentionally never resolves — surfaces a forever-pending Suspense boundary\n // when a key is requested that the loader never declared.\n});\n\n/**\n * Read a deferred promise published by `defer({ deferred: { <key>: Promise } })`\n * inside an SSR data loader. Mirror of `@real-router/react/ssr` `useDeferred`\n * — same `state.context.ssrDataDeferred` contract, same NEVER-on-missing\n * fallback. Pair with `<Await>` (this package) which adds Preact-side\n * promise-status tracking since Preact 10 has no `use(promise)` analogue.\n */\nexport function useDeferred<T = unknown>(key: string): Promise<T> {\n const { route } = useRoute();\n const context = route.context as DeferredContext;\n const deferred = context.ssrDataDeferred;\n const promise = deferred?.[key];\n\n return (promise ?? NEVER_PROMISE) as Promise<T>;\n}\n","import { useDeferred } from \"../hooks/useDeferred\";\n\nimport type { ComponentChildren } from \"preact\";\n\ninterface TrackedPromise<T> extends Promise<T> {\n status?: \"pending\" | \"fulfilled\" | \"rejected\";\n value?: T;\n reason?: unknown;\n}\n\n/**\n * Preact's `Suspense` (from `preact/compat`) catches a thrown thenable and\n * re-runs the boundary's render once it settles. For deterministic re-renders\n * we tag the promise with `.status` / `.value` / `.reason` on first access so\n * the second render-pass can return the value synchronously instead of\n * throwing again.\n *\n * The same tag layout is used by React 19's internal `use(promise)` cache,\n * so promises that already carry the tag (e.g. emitted by a Suspense-aware\n * data lib) are reused as-is.\n */\nfunction track<T>(promise: Promise<T>): TrackedPromise<T> {\n const tracked = promise as TrackedPromise<T>;\n\n if (tracked.status !== undefined) {\n return tracked;\n }\n\n tracked.status = \"pending\";\n promise.then(\n (value) => {\n /* v8 ignore next 4 -- @preserve: the `.status === \"pending\"` guard\n protects against external mutation between `track()` and the .then\n microtask; covered branch is the always-true case in our control. */\n if (tracked.status === \"pending\") {\n tracked.status = \"fulfilled\";\n tracked.value = value;\n }\n },\n /* v8 ignore start -- @preserve: rejection .then handler — tested\n end-to-end via the React adapter's e2e ssr-streaming Scenario 10\n (id=4 reviews promise rejects on the wire); covering it in unit tests\n requires Preact's Suspense to surface the rejection through render,\n which doesn't compose cleanly with vitest's unhandled-rejection\n detector. Behaviour is symmetric to the success handler above. */\n (error: unknown) => {\n if (tracked.status === \"pending\") {\n tracked.status = \"rejected\";\n tracked.reason = error;\n }\n },\n /* v8 ignore stop */\n );\n\n return tracked;\n}\n\nexport interface AwaitProps<T> {\n /** Deferred key declared in the loader's `defer({ deferred: { <name>: ... } })`. */\n readonly name: string;\n /** Render the resolved value. Suspends while pending; throws inside the\n * nearest Error Boundary on rejection. */\n readonly children: (value: T) => ComponentChildren;\n}\n\n/**\n * Reads `useDeferred(name)` and hands the resolved value to the render-prop\n * via Preact's `<Suspense>`-throwing convention. Wrap in `<Streamed>` (or\n * `<Suspense>` from `preact/compat`).\n *\n * ```tsx\n * <Streamed fallback={<Spinner />}>\n * <Await<Review[]> name=\"reviews\">\n * {(reviews) => <ReviewList items={reviews} />}\n * </Await>\n * </Streamed>\n * ```\n */\nexport function Await<T = unknown>({\n name,\n children,\n}: AwaitProps<T>): ComponentChildren {\n const promise = useDeferred<T>(name);\n const tracked = track(promise);\n\n if (tracked.status === \"fulfilled\") {\n return children(tracked.value as T);\n }\n\n if (tracked.status === \"rejected\") {\n throw tracked.reason;\n }\n\n // Suspense catches the thrown thenable and waits for resolution. ESLint\n // complains because Promises aren't Errors, but Preact's Suspense (like\n // React's pre-`use()` Suspense convention) explicitly expects a thenable.\n // eslint-disable-next-line @typescript-eslint/only-throw-error -- Suspense thenable convention\n throw promise;\n}\n","import { Suspense } from \"preact/compat\";\n\nimport type { ComponentChildren } from \"preact\";\n\nexport interface StreamedProps {\n /** Shown while any descendant `<Await>` / `use(promise)`-equivalent suspends. */\n readonly fallback: ComponentChildren;\n readonly children: ComponentChildren;\n}\n\n/**\n * Cross-adapter alias for `<Suspense fallback={…}>` from `preact/compat`.\n * Pairs with `<Await>` for symmetry with the React/Solid/Svelte/Vue/Angular\n * SSR streaming naming.\n *\n * Preact's `Suspense` is part of `preact/compat` (experimental). For\n * production streaming the preact-render-to-string toolchain is required.\n */\nexport function Streamed({\n fallback,\n children,\n}: StreamedProps): ComponentChildren {\n return <Suspense fallback={fallback}>{children}</Suspense>;\n}\n","import { createContext } from \"preact\";\n\nimport type { HttpStatusSink } from \"../utils/createHttpStatusSink\";\nimport type { ComponentChildren } from \"preact\";\n\nexport const HttpStatusContext = createContext<HttpStatusSink | null>(null);\n\nexport interface HttpStatusProviderProps {\n readonly sink: HttpStatusSink;\n readonly children: ComponentChildren;\n}\n\nexport function HttpStatusProvider({\n sink,\n children,\n}: HttpStatusProviderProps): ComponentChildren {\n return (\n <HttpStatusContext.Provider value={sink}>\n {children}\n </HttpStatusContext.Provider>\n );\n}\n","import { useContext } from \"preact/hooks\";\n\nimport { HttpStatusContext } from \"./HttpStatusProvider\";\n\nimport type { ComponentChildren } from \"preact\";\n\nexport interface HttpStatusCodeProps {\n /** HTTP status to apply to the response. Common values: 404, 410, 451, 503. */\n readonly code: number;\n}\n\n/**\n * Render-time HTTP status declaration. Mount inside a route component (typical\n * use case: a glob `*` route's NotFound page) when the status is decided by\n * the rendered tree rather than a loader.\n *\n * Writes `code` to the nearest `<HttpStatusProvider>`'s sink during render and\n * returns `null`. With no provider mounted (the standard client-side case)\n * the component is a silent no-op — same component tree hydrates without\n * touching the DOM or warning about mismatches.\n *\n * Loader-driven errors (`LoaderNotFound` → 404, `LoaderRedirect` → 30x) keep\n * working as before; this component covers render-time decisions only.\n *\n * Last write wins when several `<HttpStatusCode />` instances mount in the\n * same render pass — sink reflects the last component that ran.\n *\n * ```tsx\n * // entry-server.tsx\n * import { renderToString } from \"preact-render-to-string\";\n * import { createHttpStatusSink, HttpStatusProvider } from \"@real-router/preact/ssr\";\n *\n * const sink = createHttpStatusSink();\n * const html = renderToString(\n * <HttpStatusProvider sink={sink}>\n * <RouterProvider router={router}>\n * <App />\n * </RouterProvider>\n * </HttpStatusProvider>,\n * );\n * response.status(sink.code ?? 200).send(html);\n * ```\n *\n * **Streaming SSR (`renderToReadableStream`):** the response status MUST be\n * sent before the first body byte flushes. If `<HttpStatusCode />` is mounted\n * inside a late-resolving `<Suspense>` boundary, the sink write may happen\n * AFTER the headers are already on the wire — the override is then lost.\n * Mount the component in the shell (above every `<Suspense>` that could\n * delay it). For non-streaming SSR (`renderToString` / `renderToStringAsync`)\n * there is no such ordering concern.\n *\n * **Valid `code` range:** Node's `res.end()` throws `Invalid status code` on\n * `NaN`, `0`, negative values, or values `> 999` — this surfaces as a 5xx /\n * dropped connection, not silent corruption. Pass a real HTTP status integer\n * (commonly 4xx/5xx; 100-999 is what Node accepts).\n */\nexport function HttpStatusCode({\n code,\n}: HttpStatusCodeProps): ComponentChildren {\n const sink = useContext(HttpStatusContext);\n\n if (sink) {\n // Dev-only validation: Node's `res.end()` throws `Invalid status code` on\n // NaN / 0 / negative / non-integer / >999. Surface the bad value at the\n // source so the consumer can fix the routing logic, instead of waiting\n // for the server to crash mid-response. Production builds (Vite, esbuild,\n // tsdown all replace `process.env.NODE_ENV !== \"production\"` with `false`)\n // strip the check.\n if (\n process.env.NODE_ENV !== \"production\" &&\n (!Number.isInteger(code) || code < 100 || code > 999)\n ) {\n console.error(\n `[real-router] <HttpStatusCode code={${String(code)}} /> received an invalid HTTP status code. Node's res.end() rejects values that are not an integer in [100, 999] — pass a real HTTP status (commonly 4xx/5xx).`,\n );\n }\n\n sink.code = code;\n }\n\n return null;\n}\n","/**\n * Render-scoped HTTP status sink. Created per request on the server, passed to\n * `<HttpStatusProvider sink={...}>`, and read after `renderToString` (or the\n * Preact streaming helper) to apply the value to the HTTP response.\n *\n * Last write wins: if the rendered tree mounts more than one\n * `<HttpStatusCode />`, the value reflects the last component that ran during\n * the render pass.\n *\n * No-op on the client — `<HttpStatusCode />` reads the optional context and\n * skips the write when no provider is mounted, so the same component tree can\n * be hydrated without changing behaviour.\n *\n * Constraints:\n * - **Per-request only.** Don't share a sink across requests; the rendered\n * tree mutates `code` in place. Module-level singletons leak status\n * between concurrent requests.\n * - **Don't `Object.freeze` the sink.** The component writes to `.code`;\n * freezing makes the assignment throw under ESM strict mode.\n */\nexport interface HttpStatusSink {\n code: number | undefined;\n}\n\nexport function createHttpStatusSink(): HttpStatusSink {\n return { code: undefined };\n}\n"],"mappings":"0NASA,SAAgB,EAAW,CACzB,WACA,WAAW,MAC0B,CACrC,GAAM,CAAC,EAAS,IAAA,EAAA,EAAA,UAAuB,EAAK,EAU5C,OARA,EAAA,EAAA,eAAgB,CAKd,EAAW,EAAI,CACjB,EAAG,CAAC,CAAC,EAEE,EAAU,EAAW,CAC9B,CCfA,SAAgB,EAAW,CACzB,WACA,WAAW,MAC0B,CACrC,GAAM,CAAC,EAAS,IAAA,EAAA,EAAA,UAAuB,EAAK,EAW5C,OATA,EAAA,EAAA,eAAgB,CAMd,EAAW,EAAI,CACjB,EAAG,CAAC,CAAC,EAEE,EAAU,EAAW,CAC9B,CCnBA,MAAM,EAAgB,IAAI,YAAqB,CAG/C,CAAC,EASD,SAAgB,EAAyB,EAAyB,CAChE,GAAM,CAAE,SAAUA,EAAAA,EAAS,EAK3B,OAJgB,EAAM,QACG,kBACE,IAER,CACrB,CCJA,SAAS,EAAS,EAAwC,CACxD,IAAM,EAAU,EAgChB,OA9BI,EAAQ,SAAW,IAAA,IAIvB,EAAQ,OAAS,UACjB,EAAQ,KACL,GAAU,CAIL,EAAQ,SAAW,YACrB,EAAQ,OAAS,YACjB,EAAQ,MAAQ,EAEpB,EAOC,GAAmB,CACd,EAAQ,SAAW,YACrB,EAAQ,OAAS,WACjB,EAAQ,OAAS,EAErB,CAEF,EAEO,GA7BE,CA8BX,CAuBA,SAAgB,EAAmB,CACjC,OACA,YACmC,CACnC,IAAM,EAAU,EAAe,CAAI,EAC7B,EAAU,EAAM,CAAO,EAE7B,GAAI,EAAQ,SAAW,YACrB,OAAO,EAAS,EAAQ,KAAU,EAWpC,MARI,EAAQ,SAAW,WACf,EAAQ,OAOV,CACR,CChFA,SAAgB,EAAS,CACvB,WACA,YACmC,CACnC,OAAO,EAAA,EAAA,KAACC,EAAAA,SAAD,CAAoB,WAAW,UAAmB,CAAA,CAC3D,CClBA,MAAa,GAAA,EAAA,EAAA,eAAyD,IAAI,EAO1E,SAAgB,EAAmB,CACjC,OACA,YAC6C,CAC7C,OACE,EAAA,EAAA,KAAC,EAAkB,SAAnB,CAA4B,MAAO,EAChC,UACyB,CAAA,CAEhC,CCmCA,SAAgB,EAAe,CAC7B,QACyC,CACzC,IAAM,GAAA,EAAA,EAAA,YAAkB,CAAiB,EAqBzC,OAnBI,IAQA,QAAQ,IAAI,WAAa,eACxB,CAAC,OAAO,UAAU,CAAI,GAAK,EAAO,KAAO,EAAO,MAEjD,QAAQ,MACN,uCAAuC,OAAO,CAAI,EAAE,+JACtD,EAGF,EAAK,KAAO,GAGP,IACT,CCzDA,SAAgB,GAAuC,CACrD,MAAO,CAAE,KAAM,IAAA,EAAU,CAC3B"}
1
+ {"version":3,"file":"ssr.js","names":["useRoute","Suspense"],"sources":["../../src/components/ClientOnly.tsx","../../src/components/ServerOnly.tsx","../../src/hooks/useDeferred.tsx","../../src/components/Await.tsx","../../src/components/Streamed.tsx","../../src/components/HttpStatusProvider.tsx","../../src/components/HttpStatusCode.tsx","../../src/utils/createHttpStatusSink.ts"],"sourcesContent":["import { useEffect, useState } from \"preact/hooks\";\n\nimport type { ComponentChildren } from \"preact\";\n\nexport interface ClientOnlyProps {\n readonly children: ComponentChildren;\n readonly fallback?: ComponentChildren;\n}\n\nexport function ClientOnly({\n children,\n fallback = null,\n}: ClientOnlyProps): ComponentChildren {\n const [mounted, setMounted] = useState(false);\n\n useEffect(() => {\n // SSR/hydration boundary: server emits the fallback branch, client matches\n // it on first paint, then this effect flips state to swap in the children.\n // The intentional re-render is what makes the markup match across renders.\n // eslint-disable-next-line @eslint-react/set-state-in-effect -- intentional post-hydration swap\n setMounted(true);\n }, []);\n\n return mounted ? children : fallback;\n}\n","import { useEffect, useState } from \"preact/hooks\";\n\nimport type { ComponentChildren } from \"preact\";\n\nexport interface ServerOnlyProps {\n readonly children: ComponentChildren;\n readonly fallback?: ComponentChildren;\n}\n\nexport function ServerOnly({\n children,\n fallback = null,\n}: ServerOnlyProps): ComponentChildren {\n const [mounted, setMounted] = useState(false);\n\n useEffect(() => {\n // SSR/hydration boundary: server emits the children branch, client matches\n // it on first paint, then this effect flips state to swap in the fallback\n // (or hide entirely). The intentional re-render keeps markup consistent\n // across renders.\n // eslint-disable-next-line @eslint-react/set-state-in-effect -- intentional post-hydration swap\n setMounted(true);\n }, []);\n\n return mounted ? fallback : children;\n}\n","import { useRoute } from \"./useRoute\";\n\ninterface DeferredContext {\n ssrDataDeferred?: Record<string, Promise<unknown>>;\n}\n\nconst NEVER_PROMISE = new Promise<never>(() => {\n // Intentionally never resolves — surfaces a forever-pending Suspense boundary\n // when a key is requested that the loader never declared.\n});\n\n/**\n * Read a deferred promise published by `defer({ deferred: { <key>: Promise } })`\n * inside an SSR data loader. Mirror of `@real-router/react/ssr` `useDeferred`\n * — same `state.context.ssrDataDeferred` contract, same NEVER-on-missing\n * fallback. Pair with `<Await>` (this package) which adds Preact-side\n * promise-status tracking since Preact 10 has no `use(promise)` analogue.\n */\nexport function useDeferred<T = unknown>(key: string): Promise<T> {\n const { route } = useRoute();\n const context = route.context as DeferredContext;\n const deferred = context.ssrDataDeferred;\n const promise = deferred?.[key];\n\n return (promise ?? NEVER_PROMISE) as Promise<T>;\n}\n","import { useDeferred } from \"../hooks/useDeferred\";\n\nimport type { ComponentChildren } from \"preact\";\n\ninterface TrackedPromise<T> extends Promise<T> {\n status?: \"pending\" | \"fulfilled\" | \"rejected\";\n value?: T;\n reason?: unknown;\n}\n\n/**\n * Preact's `Suspense` (from `preact/compat`) catches a thrown thenable and\n * re-runs the boundary's render once it settles. For deterministic re-renders\n * we tag the promise with `.status` / `.value` / `.reason` on first access so\n * the second render-pass can return the value synchronously instead of\n * throwing again.\n *\n * The same tag layout is used by React 19's internal `use(promise)` cache,\n * so promises that already carry the tag (e.g. emitted by a Suspense-aware\n * data lib) are reused as-is.\n */\nfunction track<T>(promise: Promise<T>): TrackedPromise<T> {\n const tracked = promise as TrackedPromise<T>;\n\n if (tracked.status !== undefined) {\n return tracked;\n }\n\n tracked.status = \"pending\";\n promise.then(\n (value) => {\n /* v8 ignore next 4 -- @preserve: the `.status === \"pending\"` guard\n protects against external mutation between `track()` and the .then\n microtask; covered branch is the always-true case in our control. */\n if (tracked.status === \"pending\") {\n tracked.status = \"fulfilled\";\n tracked.value = value;\n }\n },\n /* v8 ignore start -- @preserve: rejection .then handler — tested\n end-to-end via the React adapter's e2e ssr-streaming Scenario 10\n (id=4 reviews promise rejects on the wire); covering it in unit tests\n requires Preact's Suspense to surface the rejection through render,\n which doesn't compose cleanly with vitest's unhandled-rejection\n detector. Behaviour is symmetric to the success handler above. */\n (error: unknown) => {\n if (tracked.status === \"pending\") {\n tracked.status = \"rejected\";\n tracked.reason = error;\n }\n },\n /* v8 ignore stop */\n );\n\n return tracked;\n}\n\nexport interface AwaitProps<T> {\n /** Deferred key declared in the loader's `defer({ deferred: { <name>: ... } })`. */\n readonly name: string;\n /** Render the resolved value. Suspends while pending; throws inside the\n * nearest Error Boundary on rejection. */\n readonly children: (value: T) => ComponentChildren;\n}\n\n/**\n * Reads `useDeferred(name)` and hands the resolved value to the render-prop\n * via Preact's `<Suspense>`-throwing convention. Wrap in `<Streamed>` (or\n * `<Suspense>` from `preact/compat`).\n *\n * ```tsx\n * <Streamed fallback={<Spinner />}>\n * <Await<Review[]> name=\"reviews\">\n * {(reviews) => <ReviewList items={reviews} />}\n * </Await>\n * </Streamed>\n * ```\n */\nexport function Await<T = unknown>({\n name,\n children,\n}: AwaitProps<T>): ComponentChildren {\n const promise = useDeferred<T>(name);\n const tracked = track(promise);\n\n if (tracked.status === \"fulfilled\") {\n return children(tracked.value as T);\n }\n\n if (tracked.status === \"rejected\") {\n throw tracked.reason;\n }\n\n // Suspense catches the thrown thenable and waits for resolution. ESLint\n // complains because Promises aren't Errors, but Preact's Suspense (like\n // React's pre-`use()` Suspense convention) explicitly expects a thenable.\n // eslint-disable-next-line @typescript-eslint/only-throw-error -- Suspense thenable convention\n throw promise;\n}\n","import { Suspense } from \"preact/compat\";\n\nimport type { ComponentChildren } from \"preact\";\n\nexport interface StreamedProps {\n /** Shown while any descendant `<Await>` / `use(promise)`-equivalent suspends. */\n readonly fallback: ComponentChildren;\n readonly children: ComponentChildren;\n}\n\n/**\n * Cross-adapter alias for `<Suspense fallback={…}>` from `preact/compat`.\n * Pairs with `<Await>` for symmetry with the React/Solid/Svelte/Vue/Angular\n * SSR streaming naming.\n *\n * Preact's `Suspense` is part of `preact/compat` (experimental). For\n * production streaming the preact-render-to-string toolchain is required.\n */\nexport function Streamed({\n fallback,\n children,\n}: StreamedProps): ComponentChildren {\n return <Suspense fallback={fallback}>{children}</Suspense>;\n}\n","import { createContext } from \"preact\";\n\nimport type { HttpStatusSink } from \"../utils/createHttpStatusSink\";\nimport type { ComponentChildren } from \"preact\";\n\nexport const HttpStatusContext = createContext<HttpStatusSink | null>(null);\n\nexport interface HttpStatusProviderProps {\n readonly sink: HttpStatusSink;\n readonly children: ComponentChildren;\n}\n\nexport function HttpStatusProvider({\n sink,\n children,\n}: HttpStatusProviderProps): ComponentChildren {\n return (\n <HttpStatusContext.Provider value={sink}>\n {children}\n </HttpStatusContext.Provider>\n );\n}\n","import { useContext } from \"preact/hooks\";\n\nimport { HttpStatusContext } from \"./HttpStatusProvider\";\n\nimport type { ComponentChildren } from \"preact\";\n\nexport interface HttpStatusCodeProps {\n /** HTTP status to apply to the response. Common values: 404, 410, 451, 503. */\n readonly code: number;\n}\n\n/**\n * Render-time HTTP status declaration. Mount inside a route component (typical\n * use case: a glob `*` route's NotFound page) when the status is decided by\n * the rendered tree rather than a loader.\n *\n * Writes `code` to the nearest `<HttpStatusProvider>`'s sink during render and\n * returns `null`. With no provider mounted (the standard client-side case)\n * the component is a silent no-op — same component tree hydrates without\n * touching the DOM or warning about mismatches.\n *\n * Loader-driven errors (`LoaderNotFound` → 404, `LoaderRedirect` → 30x) keep\n * working as before; this component covers render-time decisions only.\n *\n * Last write wins when several `<HttpStatusCode />` instances mount in the\n * same render pass — sink reflects the last component that ran.\n *\n * ```tsx\n * // entry-server.tsx\n * import { renderToString } from \"preact-render-to-string\";\n * import { createHttpStatusSink, HttpStatusProvider } from \"@real-router/preact/ssr\";\n *\n * const sink = createHttpStatusSink();\n * const html = renderToString(\n * <HttpStatusProvider sink={sink}>\n * <RouterProvider router={router}>\n * <App />\n * </RouterProvider>\n * </HttpStatusProvider>,\n * );\n * response.status(sink.code ?? 200).send(html);\n * ```\n *\n * **Streaming SSR (`renderToReadableStream`):** the response status MUST be\n * sent before the first body byte flushes. If `<HttpStatusCode />` is mounted\n * inside a late-resolving `<Suspense>` boundary, the sink write may happen\n * AFTER the headers are already on the wire — the override is then lost.\n * Mount the component in the shell (above every `<Suspense>` that could\n * delay it). For non-streaming SSR (`renderToString` / `renderToStringAsync`)\n * there is no such ordering concern.\n *\n * **Valid `code` range:** Node's `res.end()` throws `Invalid status code` on\n * `NaN`, `0`, negative values, or values `> 999` — this surfaces as a 5xx /\n * dropped connection, not silent corruption. Pass a real HTTP status integer\n * (commonly 4xx/5xx; 100-999 is what Node accepts).\n */\nexport function HttpStatusCode({\n code,\n}: HttpStatusCodeProps): ComponentChildren {\n const sink = useContext(HttpStatusContext);\n\n if (sink) {\n // Dev-only validation: Node's `res.end()` throws `Invalid status code` on\n // NaN / 0 / negative / non-integer / >999. Surface the bad value at the\n // source so the consumer can fix the routing logic, instead of waiting\n // for the server to crash mid-response. Production builds (Vite, esbuild,\n // tsdown all replace `process.env.NODE_ENV !== \"production\"` with `false`)\n // strip the check.\n if (\n process.env.NODE_ENV !== \"production\" &&\n (!Number.isInteger(code) || code < 100 || code > 999)\n ) {\n console.error(\n `[real-router] <HttpStatusCode code={${String(code)}} /> received an invalid HTTP status code. Node's res.end() rejects values that are not an integer in [100, 999] — pass a real HTTP status (commonly 4xx/5xx).`,\n );\n }\n\n sink.code = code;\n }\n\n return null;\n}\n","/**\n * Render-scoped HTTP status sink. Created per request on the server, passed to\n * `<HttpStatusProvider sink={...}>`, and read after `renderToString` (or the\n * Preact streaming helper) to apply the value to the HTTP response.\n *\n * Last write wins: if the rendered tree mounts more than one\n * `<HttpStatusCode />`, the value reflects the last component that ran during\n * the render pass.\n *\n * No-op on the client — `<HttpStatusCode />` reads the optional context and\n * skips the write when no provider is mounted, so the same component tree can\n * be hydrated without changing behaviour.\n *\n * Constraints:\n * - **Per-request only.** Don't share a sink across requests; the rendered\n * tree mutates `code` in place. Module-level singletons leak status\n * between concurrent requests.\n * - **Don't `Object.freeze` the sink.** The component writes to `.code`;\n * freezing makes the assignment throw under ESM strict mode.\n */\nexport interface HttpStatusSink {\n code: number | undefined;\n}\n\nexport function createHttpStatusSink(): HttpStatusSink {\n return { code: undefined };\n}\n"],"mappings":"0NASA,SAAgB,EAAW,CACzB,WACA,WAAW,MAC0B,CACrC,GAAM,CAAC,EAAS,IAAA,EAAA,EAAA,SAAA,CAAuB,EAAK,EAU5C,OARA,EAAA,EAAA,UAAA,KAAgB,CAKd,EAAW,EAAI,CACjB,EAAG,CAAC,CAAC,EAEE,EAAU,EAAW,CAC9B,CCfA,SAAgB,EAAW,CACzB,WACA,WAAW,MAC0B,CACrC,GAAM,CAAC,EAAS,IAAA,EAAA,EAAA,SAAA,CAAuB,EAAK,EAW5C,OATA,EAAA,EAAA,UAAA,KAAgB,CAMd,EAAW,EAAI,CACjB,EAAG,CAAC,CAAC,EAEE,EAAU,EAAW,CAC9B,CCnBA,MAAM,EAAgB,IAAI,YAAqB,CAG/C,CAAC,EASD,SAAgB,EAAyB,EAAyB,CAChE,GAAM,CAAE,SAAUA,EAAAA,EAAS,EAK3B,OAJgB,EAAM,QACG,kBACE,IAER,CACrB,CCJA,SAAS,EAAS,EAAwC,CACxD,IAAM,EAAU,EAgChB,OA9BI,EAAQ,SAAW,IAAA,IAIvB,EAAQ,OAAS,UACjB,EAAQ,KACL,GAAU,CAIL,EAAQ,SAAW,YACrB,EAAQ,OAAS,YACjB,EAAQ,MAAQ,EAEpB,EAOC,GAAmB,CACd,EAAQ,SAAW,YACrB,EAAQ,OAAS,WACjB,EAAQ,OAAS,EAErB,CAEF,EAEO,GA7BE,CA8BX,CAuBA,SAAgB,EAAmB,CACjC,OACA,YACmC,CACnC,IAAM,EAAU,EAAe,CAAI,EAC7B,EAAU,EAAM,CAAO,EAE7B,GAAI,EAAQ,SAAW,YACrB,OAAO,EAAS,EAAQ,KAAU,EAWpC,MARI,EAAQ,SAAW,WACf,EAAQ,OAOV,CACR,CChFA,SAAgB,EAAS,CACvB,WACA,YACmC,CACnC,OAAO,EAAA,EAAA,IAAA,CAACC,EAAAA,SAAD,CAAoB,WAAW,UAAmB,CAAA,CAC3D,CClBA,MAAa,GAAA,EAAA,EAAA,cAAA,CAAyD,IAAI,EAO1E,SAAgB,EAAmB,CACjC,OACA,YAC6C,CAC7C,OACE,EAAA,EAAA,IAAA,CAAC,EAAkB,SAAnB,CAA4B,MAAO,EAChC,UACyB,CAAA,CAEhC,CCmCA,SAAgB,EAAe,CAC7B,QACyC,CACzC,IAAM,GAAA,EAAA,EAAA,WAAA,CAAkB,CAAiB,EAqBzC,OAnBI,IAQA,QAAQ,IAAI,WAAa,eACxB,CAAC,OAAO,UAAU,CAAI,GAAK,EAAO,KAAO,EAAO,MAEjD,QAAQ,MACN,uCAAuC,OAAO,CAAI,EAAE,+JACtD,EAGF,EAAK,KAAO,GAGP,IACT,CCzDA,SAAgB,GAAuC,CACrD,MAAO,CAAE,KAAM,IAAA,EAAU,CAC3B"}
@@ -1 +1 @@
1
- {"version":3,"file":"useRoute-B0pDCgZw.js","names":[],"sources":["../../src/context.ts","../../src/hooks/useRoute.tsx"],"sourcesContent":["import { createContext } from \"preact\";\nimport { useContext } from \"preact/hooks\";\n\nimport type { RouteContext as RouteContextType } from \"./types\";\nimport type { Router, Navigator } from \"@real-router/core\";\nimport type { Context } from \"preact\";\n\nexport const RouteContext = createContext<RouteContextType | null>(null);\n\nexport const RouterContext = createContext<Router | null>(null);\n\nexport const NavigatorContext = createContext<Navigator | null>(null);\n\nexport function createUseContextOrThrow<T>(\n context: Context<T | null>,\n hookName: string,\n): () => T {\n return () => {\n const value = useContext(context);\n\n if (!value) {\n throw new Error(`${hookName} must be used within a RouterProvider`);\n }\n\n return value;\n };\n}\n","import { createUseContextOrThrow, RouteContext } from \"../context\";\n\nimport type { RouteContext as RouteContextType } from \"../types\";\nimport type { Params, State } from \"@real-router/core\";\n\nconst useRouteContextOrThrow = createUseContextOrThrow(\n RouteContext,\n \"useRoute\",\n);\n\nexport const useRoute = <P extends Params = Params>(): Omit<\n RouteContextType<P>,\n \"route\"\n> & { route: State<P> } => {\n const routeContext = useRouteContextOrThrow();\n\n if (!routeContext.route) {\n throw new Error(\n \"useRoute called with no active route. Did you forget to await router.start() before rendering, or is the router stopped/disposed?\",\n );\n }\n\n return routeContext as Omit<RouteContextType<P>, \"route\"> & {\n route: State<P>;\n };\n};\n"],"mappings":"kDAOA,MAAa,GAAA,EAAA,EAAA,eAAsD,IAAI,EAE1D,GAAA,EAAA,EAAA,eAA6C,IAAI,EAEjD,GAAA,EAAA,EAAA,eAAmD,IAAI,EAEpE,SAAgB,EACd,EACA,EACS,CACT,UAAa,CACX,IAAM,GAAA,EAAA,EAAA,YAAmB,CAAO,EAEhC,GAAI,CAAC,EACH,MAAU,MAAM,GAAG,EAAS,sCAAsC,EAGpE,OAAO,CACT,CACF,CCrBA,MAAM,EAAyB,EAC7B,EACA,UACF,EAEa,MAGc,CACzB,IAAM,EAAe,EAAuB,EAE5C,GAAI,CAAC,EAAa,MAChB,MAAU,MACR,mIACF,EAGF,OAAO,CAGT"}
1
+ {"version":3,"file":"useRoute-B0pDCgZw.js","names":[],"sources":["../../src/context.ts","../../src/hooks/useRoute.tsx"],"sourcesContent":["import { createContext } from \"preact\";\nimport { useContext } from \"preact/hooks\";\n\nimport type { RouteContext as RouteContextType } from \"./types\";\nimport type { Router, Navigator } from \"@real-router/core\";\nimport type { Context } from \"preact\";\n\nexport const RouteContext = createContext<RouteContextType | null>(null);\n\nexport const RouterContext = createContext<Router | null>(null);\n\nexport const NavigatorContext = createContext<Navigator | null>(null);\n\nexport function createUseContextOrThrow<T>(\n context: Context<T | null>,\n hookName: string,\n): () => T {\n return () => {\n const value = useContext(context);\n\n if (!value) {\n throw new Error(`${hookName} must be used within a RouterProvider`);\n }\n\n return value;\n };\n}\n","import { createUseContextOrThrow, RouteContext } from \"../context\";\n\nimport type { RouteContext as RouteContextType } from \"../types\";\nimport type { Params, State } from \"@real-router/core\";\n\nconst useRouteContextOrThrow = createUseContextOrThrow(\n RouteContext,\n \"useRoute\",\n);\n\nexport const useRoute = <P extends Params = Params>(): Omit<\n RouteContextType<P>,\n \"route\"\n> & { route: State<P> } => {\n const routeContext = useRouteContextOrThrow();\n\n if (!routeContext.route) {\n throw new Error(\n \"useRoute called with no active route. Did you forget to await router.start() before rendering, or is the router stopped/disposed?\",\n );\n }\n\n return routeContext as Omit<RouteContextType<P>, \"route\"> & {\n route: State<P>;\n };\n};\n"],"mappings":"kDAOA,MAAa,GAAA,EAAA,EAAA,cAAA,CAAsD,IAAI,EAE1D,GAAA,EAAA,EAAA,cAAA,CAA6C,IAAI,EAEjD,GAAA,EAAA,EAAA,cAAA,CAAmD,IAAI,EAEpE,SAAgB,EACd,EACA,EACS,CACT,UAAa,CACX,IAAM,GAAA,EAAA,EAAA,WAAA,CAAmB,CAAO,EAEhC,GAAI,CAAC,EACH,MAAU,MAAM,GAAG,EAAS,sCAAsC,EAGpE,OAAO,CACT,CACF,CCrBA,MAAM,EAAyB,EAC7B,EACA,UACF,EAEa,MAGc,CACzB,IAAM,EAAe,EAAuB,EAE5C,GAAI,CAAC,EAAa,MAChB,MAAU,MACR,mIACF,EAGF,OAAO,CAGT"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.mts","names":[],"sources":["../../src/components/RouteView/types.ts","../../src/components/RouteView/components.tsx","../../src/components/RouteView/RouteView.tsx","../../src/types.ts","../../src/components/Link.tsx","../../src/components/RouterErrorBoundary.tsx","../../src/hooks/useRouter.tsx","../../src/hooks/useNavigator.tsx","../../src/hooks/useRouteUtils.tsx","../../src/hooks/useRoute.tsx","../../src/hooks/useRouteNode.tsx","../../src/hooks/useRouterTransition.tsx","../../src/hooks/useRouteExit.tsx","../../src/hooks/useRouteEnter.tsx","../../../../shared/dom-utils/scroll-restore.ts","../../../../shared/dom-utils/scroll-spy.ts","../../src/RouterProvider.tsx","../../src/context.ts"],"mappings":"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"}
1
+ {"version":3,"file":"index.d.mts","names":[],"sources":["../../src/components/RouteView/types.ts","../../src/components/RouteView/components.tsx","../../src/components/RouteView/RouteView.tsx","../../src/types.ts","../../src/components/Link.tsx","../../src/components/RouterErrorBoundary.tsx","../../src/hooks/useRouter.tsx","../../src/hooks/useNavigator.tsx","../../src/hooks/useRouteUtils.tsx","../../src/hooks/useRoute.tsx","../../src/hooks/useRouteNode.tsx","../../src/hooks/useRouterTransition.tsx","../../src/hooks/useRouteExit.tsx","../../src/hooks/useRouteEnter.tsx","../../../../shared/dom-utils/scroll-restore.ts","../../../../shared/dom-utils/scroll-spy.ts","../../src/RouterProvider.tsx","../../src/context.ts"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- import{a as e,i as t,n,r,t as i}from"./useRoute-DdZuiE4J.mjs";import{useEffect as a,useLayoutEffect as o,useMemo as s,useRef as c,useState as l}from"preact/hooks";import{UNKNOWN_ROUTE as u,getNavigator as d}from"@real-router/core";import{getRouteUtils as f,startsWithSegment as p}from"@real-router/route-utils";import{Fragment as m,isValidElement as h,toChildArray as g}from"preact";import{Suspense as _,memo as v}from"preact/compat";import{Fragment as y,jsx as b,jsxs as x}from"preact/jsx-runtime";import{createActiveRouteSource as S,createDismissableError as C,createRouteNodeSource as w,createRouteSource as ee,getTransitionSource as T}from"@real-router/sources";import{getPluginApi as te}from"@real-router/core/api";function E(e){return null}E.displayName=`RouteView.Match`;function D(e){return null}D.displayName=`RouteView.Self`;function O(e){return null}O.displayName=`RouteView.NotFound`;function ne(e,t,n){return t===``?!1:n?e===t:p(e,t)}function k(e,t){for(let n of g(e))h(n)&&(n.type===E||n.type===D||n.type===O?t.push(n):k(n.props.children,t))}function A(e,t,n){return b(m,{children:n===void 0?e:b(_,{fallback:n,children:e})},t)}function re(e){return e.type===O||e.type===D}function ie(e,t){if(e.type===O){t.notFoundChildren=e.props.children;return}t.selfFound||=(t.selfChildren=e.props.children,t.selfFallback=e.props.fallback,!0)}function j(e,t,n,r){let{segment:i,exact:a=!1,fallback:o,children:s}=e.props,c=n?`${n}.${i}`:i;return!r&&ne(t,c,a)?A(s,c,o):null}function M(e,t,n,r){if(r.selfFound&&t===n){e.push(A(r.selfChildren,`__route-view-self__`,r.selfFallback));return}t===u&&r.notFoundChildren!==null&&e.push(b(m,{children:r.notFoundChildren},`__route-view-not-found__`))}function ae(e,t,n){let r={selfChildren:null,selfFallback:void 0,selfFound:!1,notFoundChildren:null},i=!1,a=[];for(let o of e){if(re(o)){ie(o,r);continue}let e=j(o,t,n,i);e!==null&&(i=!0,a.push(e))}return i||M(a,t,n,r),{rendered:a,activeMatchFound:i}}function N(e,t,n){let[r,i]=l(t);return a(()=>{let n=()=>{i(e=>{let n=t();return Object.is(e,n)?e:n})};return n(),e(n)},[e,t]),r}const P=e(n,`useNavigator`),F=e(t,`useRouter`);function I(e){let t=F(),n=P(),r=w(t,e),{route:i,previousRoute:a}=N(r.subscribe,r.getSnapshot,r.getSnapshot);return s(()=>({navigator:n,route:i,previousRoute:a}),[n,i,a])}function L({nodeName:e,children:t}){let{route:n}=I(e),r=s(()=>{let e=[];return k(t,e),e},[t]),i=n?.name,a=s(()=>i===void 0?[]:ae(r,i,e).rendered,[r,i,e]);return a.length>0?b(y,{children:a}):null}L.displayName=`RouteView`;const oe=Object.assign(L,{Match:E,Self:D,NotFound:O}),se=Object.freeze({}),R=Object.freeze({}),z=`data-real-router-announcer`,B=Object.freeze({destroy:()=>{}});function V(e,t){if(typeof document>`u`)return B;let n=t?.prefix??`Navigated to `,r=t?.getAnnouncementText,i=!0,a=!1,o=!1,s=``,c=null,l,u=H(),d=(e,t)=>{s=e,clearTimeout(l),u.textContent=e,l=setTimeout(()=>{u.textContent=``,s=``},7e3),G(t)},f=setTimeout(()=>{if(a=!0,c!==null&&!o){let e=c;c=null,d(e,document.querySelector(`h1`))}},100),p=e.subscribe(({route:e})=>{if(i){i=!1;return}requestAnimationFrame(()=>{requestAnimationFrame(()=>{if(o)return;let t=document.querySelector(`h1`),i=W(e,n,r,t);if(!(!i||i===s)){if(!a){c=i;return}d(i,t)}})})});return{destroy(){o=!0,p(),clearTimeout(l),clearTimeout(f),U()}}}function H(){let e=document.querySelector(`[${z}]`);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(z,``),(document.body??document.documentElement).prepend(t),t}function U(){document.querySelector(`[${z}]`)?.remove()}function W(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 G(e){e&&(e.hasAttribute(`tabindex`)||e.setAttribute(`tabindex`,`-1`),e.focus({preventScroll:!0}))}const K=Object.freeze({destroy:()=>{}});function ce(e,t){if(globalThis.window===void 0)return K;let n=t?.mode??`restore`;if(n===`native`)return K;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=>{if(!i){globalThis.scrollTo({top:e,left:0,behavior:a});return}let t=0,n=()=>{if(h)return;let r=i();if(r){if(r.scrollTo({top:e,left:0,behavior:a}),a!==`smooth`&&Math.abs(r.scrollTop-e)<=1)return}else globalThis.scrollTo({top:e,left:0,behavior:a});t>=10||(t+=1,requestAnimationFrame(n))};n()},m=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)},h=!1,g=!1,_=e=>{try{return le(e)}catch{return g||(g=!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(!h){if(n===`top`){m(e);return}if(e.transition.reload||r?.navigationType===`reload`){let t=_(e);p(t===null?0:c()[t]??0);return}if(r?.direction===`back`||r?.navigationType===`traverse`){let t=_(e);p(t===null?0:c()[t]??0);return}e.transition.replace||r?.navigationType===`replace`||m(e)}})}),y=()=>{let t=e.getState();if(t){let e=_(t);e!==null&&l(e,d())}};return globalThis.addEventListener(`pagehide`,y),{destroy:()=>{if(!h){h=!0,v(),globalThis.removeEventListener(`pagehide`,y);try{history.scrollRestoration=u}catch{}}}}}const q=new WeakMap;function le(e){let t=q.get(e);if(t!==void 0)return t;let n=`${e.name}:${ue(e.params)}`;return q.set(e,n),n}function ue(e){return JSON.stringify(e,de)}function de(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 J=Object.freeze({destroy:()=>{}}),Y=e=>e.context?.url,fe=e=>{let t=null,n=1/0,r=null,i=-1/0;for(let a of e){if(!a.isIntersecting)continue;let e=a.rootBounds?.top??0,o=a.boundingClientRect.top-e;o>=0?o<n&&(t=a,n=o):o>i&&(r=a,i=o)}return t??r},pe=(e,t)=>{let n=null,r=e=>{let n=e.context;n&&n.url===void 0&&(console.warn(`[real-router] scroll-spy: state.context.url is not claimed. Spy requires browser-plugin or navigation-plugin. Disabling.`),t())},i=e.getState();if(i)r(i);else{let t=!1;n=e.subscribe(({route:e})=>{t||(t=!0,r(e),n?.(),n=null)})}return{destroy(){n?.(),n=null}}},me=e=>{let t=!1,n=null,r=null,i=null,a=()=>{n!==null&&(clearTimeout(n),n=null),i&&(r??globalThis).removeEventListener(`scrollend`,i),i=null,r=null,t=!1};return{get active(){return t},start(){a(),t=!0;let o=()=>{a()};i=o,r=e(),(r??globalThis).addEventListener(`scrollend`,o,{once:!0}),n=setTimeout(o,500)},destroy(){a()}}},he=(e,t)=>{let n=null,r=null;return{schedule(){n===null&&(n=requestAnimationFrame(()=>{n=null,r!==null&&clearTimeout(r),r=setTimeout(()=>{r=null,e()},t)}))},destroy(){n!==null&&(cancelAnimationFrame(n),n=null),r!==null&&(clearTimeout(r),r=null)}}},ge=(e,t,n,r,i,a)=>{let o=new Set,s=new Map,c=!1,l=null,u=new IntersectionObserver(e=>{if(!a()){for(let t of e)s.set(t.target,t);r()}},{root:n(),rootMargin:t,threshold:0}),d=()=>{let t=n()??document,r;try{r=t.querySelectorAll(e)}catch{i();return}let a=new Set;for(let e of r){let t=e.id;t&&!c&&(a.has(t)&&(c=!0,console.warn(`[real-router] scroll-spy: duplicate id "${t}" observed. Selection picks the topmost visible match deterministically.`)),a.add(t)),!o.has(e)&&(u.observe(e),o.add(e))}},f=()=>{for(let e of o)e.isConnected||(u.unobserve(e),o.delete(e),s.delete(e));d()};d();let p=n()??document.body,m=new MutationObserver(()=>{l!==null&&clearTimeout(l),l=setTimeout(()=>{l=null,f()},250)});return m.observe(p,{childList:!0,subtree:!0,attributes:!0,attributeFilter:[`id`]}),{pending:s,destroy(){u.disconnect(),m.disconnect(),l!==null&&(clearTimeout(l),l=null),o.clear(),s.clear()}}};function _e(e,t){if(typeof document>`u`||typeof IntersectionObserver>`u`)return J;let{selector:n}=t;if(!n)return J;let r=t.rootMargin??`-20% 0px -60% 0px`,i=t.scrollContainer,a=()=>i?.()??null,o=!1,s=!1,c=!1,l=()=>s||o,u=null,d=T(e),f=pe(e,()=>{s=!0}),p=me(a),m=he(()=>{u?.()},150),h=ge(n,r,a,()=>{m.schedule()},()=>{s||(s=!0,console.warn(`[real-router] scroll-spy: invalid selector "${n}". Disabling.`))},l);u=()=>{if(o||s){h.pending.clear();return}if(d.getSnapshot().isTransitioning||p.active||h.pending.size===0)return;let t=fe(h.pending.values());if(h.pending.clear(),!t)return;let n=t.target.id;if(!n)return;let r=e.getState();if(!r||n===(Y(r)?.hash??``))return;let i={hash:n,replace:!0,force:!0,hashChange:!0};c=!0,e.navigate(r.name,r.params,i).catch(()=>{}).finally(()=>{c=!1})};let g=e.subscribe(({route:e})=>{c||Y(e)?.hashChanged&&p.start()});return{destroy(){o||(o=!0,g(),h.destroy(),m.destroy(),p.destroy(),f.destroy())}}}const ve=Object.freeze({destroy:()=>{}});function ye(e){if(typeof document>`u`||typeof document.startViewTransition!=`function`)return ve;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 be(e){return e.button===0&&!e.metaKey&&!e.altKey&&!e.ctrlKey&&!e.shiftKey}const xe=/%[\dA-Fa-f]{2}/;function Se(e){if(xe.test(e))try{return encodeURI(decodeURIComponent(e)).replaceAll(`#`,`%23`)}catch{}return encodeURI(e).replaceAll(`#`,`%23`)}function Ce(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}#${Se(a)}`:s}catch{console.error(`[real-router] Route "${t}" is not defined. The element will render without an href attribute.`);return}}function we(e,t,n,r,i){let a={...i};r!==void 0&&(a.hash=r);let o=e.getState();if(o?.name===t&&Z(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 Te=/\s/,Ee=/\S+/g;function X(e){return e?Te.test(e)?e.match(Ee)??[]:[e]:[]}function De(e,t,n){if(e&&t){let e=X(t);if(e.length===0)return n??void 0;if(!n)return e.join(` `);let r=X(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 Z(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 Oe(e,t,n=!1,r=!0,i){let a=F(),o=s(()=>i===void 0?{strict:n,ignoreQueryParams:r}:{strict:n,ignoreQueryParams:r,hash:i},[n,r,i]),c=s(()=>S(a,e,t,o),[a,e,t,o]);return N(c.subscribe,c.getSnapshot,c.getSnapshot)}function ke(e,t){return e.routeName===t.routeName&&e.className===t.className&&e.activeClassName===t.activeClassName&&e.activeStrict===t.activeStrict&&e.ignoreQueryParams===t.ignoreQueryParams&&e.onClick===t.onClick&&e.target===t.target&&e.style===t.style&&e.children===t.children&&e.hash===t.hash&&Z(e.routeParams,t.routeParams)&&Z(e.routeOptions,t.routeOptions)}const Q=v(({routeName:e,routeParams:t=se,routeOptions:n=R,className:r,activeClassName:i=`active`,activeStrict:a=!1,ignoreQueryParams:o=!0,hash:s,onClick:c,target:l,children:u,...d})=>{let f=F(),p=Oe(e,t,a,o,s),m=Ce(f,e,t,s===void 0?void 0:{hash:s}),h=r=>{c&&(c(r),r.defaultPrevented)||!be(r)||l===`_blank`||(r.preventDefault(),we(f,e,t,s,n).catch(()=>{}))},g=De(p,i,r);return b(`a`,{...d,href:m,className:g,onClick:h,children:u})},ke);Q.displayName=`Link`;function Ae({children:e,fallback:t,onError:n}){let r=C(F()),i=N(r.subscribe,r.getSnapshot,r.getSnapshot),s=c(n);return o(()=>{s.current=n}),a(()=>{i.error&&s.current?.(i.error,i.toRoute,i.fromRoute)},[i.version]),x(m,{children:[e,i.error?t(i.error,i.resetError):null]})}const $=()=>f(te(F()).getTree());function je(){let e=T(F());return N(e.subscribe,e.getSnapshot,e.getSnapshot)}function Me(e,t){let n=F(),r=c(e),i=t?.skipSameRoute??!0;o(()=>{r.current=e}),a(()=>n.subscribeLeave(({route:e,nextRoute:t,signal:n})=>{if(!(i&&e.name===t.name)&&!n.aborted)return r.current({route:e,nextRoute:t,signal:n})}),[n,i])}function Ne(e,t){let{route:n,previousRoute:r}=i(),s=c(e),l=c(null),u=t?.skipSameRoute??!0;o(()=>{s.current=e}),a(()=>{n.transition.from&&(u&&n.transition.from===n.name||l.current===n||!r||(l.current=n,s.current({route:n,previousRoute:r})))},[n,r,u])}const Pe=({router:e,children:i,announceNavigation:o,scrollRestoration:c,scrollSpy:l,viewTransitions:u})=>{a(()=>{if(!o)return;let t=V(e);return()=>{t.destroy()}},[o,e]);let f=c?.mode,p=c?.anchorScrolling,m=c?.behavior,h=c?.storageKey,g=c!==void 0;a(()=>{if(!g)return;let t=ce(e,{mode:f,anchorScrolling:p,behavior:m,storageKey:h,scrollContainer:c.scrollContainer});return()=>{t.destroy()}},[e,g,f,p,m,h]);let _=l?.selector,v=l?.rootMargin,y=l!==void 0&&_!==void 0&&_!==``;a(()=>{if(!y)return;let t=_e(e,{selector:_,rootMargin:v,scrollContainer:l.scrollContainer});return()=>{t.destroy()}},[e,y,_,v]),a(()=>{if(!u)return;let t=ye(e);return()=>{t.destroy()}},[e,u]);let x=d(e),S=s(()=>ee(e),[e]),{route:C,previousRoute:w}=N(S.subscribe,S.getSnapshot,S.getSnapshot),T=s(()=>({navigator:x,route:C,previousRoute:w}),[x,C,w]);return b(t.Provider,{value:e,children:b(n.Provider,{value:x,children:b(r.Provider,{value:T,children:i})})})};export{Q as Link,n as NavigatorContext,r as RouteContext,oe as RouteView,t as RouterContext,Ae as RouterErrorBoundary,Pe as RouterProvider,P as useNavigator,i as useRoute,Ne as useRouteEnter,Me as useRouteExit,I as useRouteNode,$ as useRouteUtils,F as useRouter,je as useRouterTransition};
1
+ import{a as e,i as t,n,r,t as i}from"./useRoute-DdZuiE4J.mjs";import{useEffect as a,useLayoutEffect as o,useMemo as s,useRef as c,useState as l}from"preact/hooks";import{UNKNOWN_ROUTE as u,getNavigator as d}from"@real-router/core";import{getRouteUtils as f,startsWithSegment as p}from"@real-router/route-utils";import{Fragment as m,isValidElement as h,toChildArray as g}from"preact";import{Suspense as _,memo as v}from"preact/compat";import{Fragment as y,jsx as b,jsxs as x}from"preact/jsx-runtime";import{createActiveRouteSource as S,createDismissableError as C,createRouteNodeSource as w,createRouteSource as ee,getTransitionSource as T}from"@real-router/sources";import{getPluginApi as te}from"@real-router/core/api";function E(e){return null}E.displayName=`RouteView.Match`;function D(e){return null}D.displayName=`RouteView.Self`;function O(e){return null}O.displayName=`RouteView.NotFound`;const ne=new Set([E,D,O]);function k(e,t,n){return t===``?!1:n?e===t:p(e,t)}function A(e,t){for(let n of g(e))h(n)&&(ne.has(n.type)?t.push(n):A(n.props.children,t))}function j(e,t,n){return b(m,{children:n===void 0?e:b(_,{fallback:n,children:e})},t)}function re(e){return e.type===O||e.type===D}function ie(e,t){if(e.type===O){t.notFoundChildren=e.props.children;return}t.selfFound||=(t.selfChildren=e.props.children,t.selfFallback=e.props.fallback,!0)}function ae(e,t,n,r){let{segment:i,exact:a=!1,fallback:o,children:s}=e.props,c=n?`${n}.${i}`:i;return!r&&k(t,c,a)?j(s,c,o):null}function oe(e,t,n,r){if(r.selfFound&&t===n){e.push(j(r.selfChildren,`__route-view-self__`,r.selfFallback));return}t===u&&r.notFoundChildren!==null&&e.push(b(m,{children:r.notFoundChildren},`__route-view-not-found__`))}function se(e,t,n){let r={selfChildren:null,selfFallback:void 0,selfFound:!1,notFoundChildren:null},i=!1,a=[];for(let o of e){if(re(o)){ie(o,r);continue}let e=ae(o,t,n,i);e!==null&&(i=!0,a.push(e))}return i||oe(a,t,n,r),{rendered:a,activeMatchFound:i}}function M(e,t,n){let[r,i]=l(t);return a(()=>{let n=()=>{i(e=>{let n=t();return Object.is(e,n)?e:n})};return n(),e(n)},[e,t]),r}const N=e(n,`useNavigator`),P=e(t,`useRouter`);function F(e){let t=P(),n=N(),r=w(t,e),{route:i,previousRoute:a}=M(r.subscribe,r.getSnapshot,r.getSnapshot);return s(()=>({navigator:n,route:i,previousRoute:a}),[n,i,a])}function I({nodeName:e,children:t}){let{route:n}=F(e),r=s(()=>{let e=[];return A(t,e),e},[t]),i=n?.name,a=s(()=>i===void 0?[]:se(r,i,e).rendered,[r,i,e]);return a.length>0?b(y,{children:a}):null}I.displayName=`RouteView`;const ce=Object.assign(I,{Match:E,Self:D,NotFound:O}),L=Object.freeze({}),R=Object.freeze({}),z=`data-real-router-announcer`,B=Object.freeze({destroy:()=>{}});function V(e,t){if(typeof document>`u`)return B;let n=t?.prefix??`Navigated to `,r=t?.getAnnouncementText,i=!0,a=!1,o=!1,s=``,c=null,l,u=H(),d=(e,t)=>{s=e,clearTimeout(l),u.textContent=e,l=setTimeout(()=>{u.textContent=``,s=``},7e3),G(t)},f=setTimeout(()=>{if(a=!0,c!==null&&!o){let e=c;c=null,d(e,document.querySelector(`h1`))}},100),p=e.subscribe(({route:e})=>{if(i){i=!1;return}requestAnimationFrame(()=>{requestAnimationFrame(()=>{if(o)return;let t=document.querySelector(`h1`),i=W(e,n,r,t);if(!(!i||i===s)){if(!a){c=i;return}d(i,t)}})})});return{destroy(){o=!0,p(),clearTimeout(l),clearTimeout(f),U()}}}function H(){let e=document.querySelector(`[${z}]`);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(z,``),(document.body??document.documentElement).prepend(t),t}function U(){document.querySelector(`[${z}]`)?.remove()}function W(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 G(e){e&&(e.hasAttribute(`tabindex`)||e.setAttribute(`tabindex`,`-1`),e.focus({preventScroll:!0}))}const K=Object.freeze({destroy:()=>{}});function le(e,t){if(globalThis.window===void 0)return K;let n=t?.mode??`restore`;if(n===`native`)return K;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=>{if(!i){globalThis.scrollTo({top:e,left:0,behavior:a});return}let t=0,n=()=>{if(h)return;let r=i();if(r){if(r.scrollTo({top:e,left:0,behavior:a}),a!==`smooth`&&Math.abs(r.scrollTop-e)<=1)return}else globalThis.scrollTo({top:e,left:0,behavior:a});t>=10||(t+=1,requestAnimationFrame(n))};n()},m=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)},h=!1,g=!1,_=e=>{try{return ue(e)}catch{return g||(g=!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(!h){if(n===`top`){m(e);return}if(e.transition.reload||r?.navigationType===`reload`){let t=_(e);p(t===null?0:c()[t]??0);return}if(r?.direction===`back`||r?.navigationType===`traverse`){let t=_(e);p(t===null?0:c()[t]??0);return}e.transition.replace||r?.navigationType===`replace`||m(e)}})}),y=()=>{let t=e.getState();if(t){let e=_(t);e!==null&&l(e,d())}};return globalThis.addEventListener(`pagehide`,y),{destroy:()=>{if(!h){h=!0,v(),globalThis.removeEventListener(`pagehide`,y);try{history.scrollRestoration=u}catch{}}}}}const q=new WeakMap;function ue(e){let t=q.get(e);if(t!==void 0)return t;let n=`${e.name}:${de(e.params)}`;return q.set(e,n),n}function de(e){return JSON.stringify(e,fe)}function fe(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 J=Object.freeze({destroy:()=>{}}),Y=e=>e.context?.url,pe=e=>{let t=null,n=1/0,r=null,i=-1/0;for(let a of e){if(!a.isIntersecting)continue;let e=a.rootBounds?.top??0,o=a.boundingClientRect.top-e;o>=0?o<n&&(t=a,n=o):o>i&&(r=a,i=o)}return t??r},X=(e,t)=>{let n=null,r=e=>{let n=e.context;n&&n.url===void 0&&(console.warn(`[real-router] scroll-spy: state.context.url is not claimed. Spy requires browser-plugin or navigation-plugin. Disabling.`),t())},i=e.getState();if(i)r(i);else{let t=!1;n=e.subscribe(({route:e})=>{t||(t=!0,r(e),n?.(),n=null)})}return{destroy(){n?.(),n=null}}},me=e=>{let t=!1,n=null,r=null,i=null,a=()=>{n!==null&&(clearTimeout(n),n=null),i&&(r??globalThis).removeEventListener(`scrollend`,i),i=null,r=null,t=!1};return{get active(){return t},start(){a(),t=!0;let o=()=>{a()};i=o,r=e(),(r??globalThis).addEventListener(`scrollend`,o,{once:!0}),n=setTimeout(o,500)},destroy(){a()}}},he=(e,t)=>{let n=null,r=null;return{schedule(){n===null&&(n=requestAnimationFrame(()=>{n=null,r!==null&&clearTimeout(r),r=setTimeout(()=>{r=null,e()},t)}))},destroy(){n!==null&&(cancelAnimationFrame(n),n=null),r!==null&&(clearTimeout(r),r=null)}}},ge=(e,t,n,r,i,a)=>{let o=new Set,s=new Map,c=!1,l=null,u=new IntersectionObserver(e=>{if(!a()){for(let t of e)s.set(t.target,t);r()}},{root:n(),rootMargin:t,threshold:0}),d=()=>{let t=n()??document,r;try{r=t.querySelectorAll(e)}catch{i();return}let a=new Set;for(let e of r){let t=e.id;t&&!c&&(a.has(t)&&(c=!0,console.warn(`[real-router] scroll-spy: duplicate id "${t}" observed. Selection picks the topmost visible match deterministically.`)),a.add(t)),!o.has(e)&&(u.observe(e),o.add(e))}},f=()=>{for(let e of o)e.isConnected||(u.unobserve(e),o.delete(e),s.delete(e));d()};d();let p=n()??document.body,m=new MutationObserver(()=>{l!==null&&clearTimeout(l),l=setTimeout(()=>{l=null,f()},250)});return m.observe(p,{childList:!0,subtree:!0,attributes:!0,attributeFilter:[`id`]}),{pending:s,destroy(){u.disconnect(),m.disconnect(),l!==null&&(clearTimeout(l),l=null),o.clear(),s.clear()}}};function _e(e,t){if(typeof document>`u`||typeof IntersectionObserver>`u`)return J;let{selector:n}=t;if(!n)return J;let r=t.rootMargin??`-20% 0px -60% 0px`,i=t.scrollContainer,a=()=>i?.()??null,o=!1,s=!1,c=!1,l=()=>s||o,u=null,d=T(e),f=X(e,()=>{s=!0}),p=me(a),m=he(()=>{u?.()},150),h=ge(n,r,a,()=>{m.schedule()},()=>{s||(s=!0,console.warn(`[real-router] scroll-spy: invalid selector "${n}". Disabling.`))},l);u=()=>{if(o||s){h.pending.clear();return}if(d.getSnapshot().isTransitioning||p.active||h.pending.size===0)return;let t=pe(h.pending.values());if(h.pending.clear(),!t)return;let n=t.target.id;if(!n)return;let r=e.getState();if(!r||n===(Y(r)?.hash??``))return;let i={hash:n,replace:!0,force:!0,hashChange:!0};c=!0,e.navigate(r.name,r.params,i).catch(()=>{}).finally(()=>{c=!1})};let g=e.subscribe(({route:e})=>{c||Y(e)?.hashChanged&&p.start()});return{destroy(){o||(o=!0,g(),h.destroy(),m.destroy(),p.destroy(),f.destroy())}}}const ve=Object.freeze({destroy:()=>{}});function ye(e){if(typeof document>`u`||typeof document.startViewTransition!=`function`)return ve;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 be(e){return e.button===0&&!e.metaKey&&!e.altKey&&!e.ctrlKey&&!e.shiftKey}const xe=/%[\dA-Fa-f]{2}/;function Se(e){if(xe.test(e))try{return encodeURI(decodeURIComponent(e)).replaceAll(`#`,`%23`)}catch{}return encodeURI(e).replaceAll(`#`,`%23`)}function Ce(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}#${Se(a)}`:s}catch{console.error(`[real-router] Route "${t}" is not defined. The element will render without an href attribute.`);return}}function we(e,t,n,r,i){let a={...i};r!==void 0&&(a.hash=r);let o=e.getState();if(o?.name===t&&Q(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 Te=/\s/,Ee=/\S+/g;function Z(e){return e?Te.test(e)?e.match(Ee)??[]:[e]:[]}function De(e,t,n){if(e&&t){let e=Z(t);if(e.length===0)return n??void 0;if(!n)return e.join(` `);let r=Z(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 Q(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 Oe(e,t,n=!1,r=!0,i){let a=P(),o=s(()=>i===void 0?{strict:n,ignoreQueryParams:r}:{strict:n,ignoreQueryParams:r,hash:i},[n,r,i]),c=s(()=>S(a,e,t,o),[a,e,t,o]);return M(c.subscribe,c.getSnapshot,c.getSnapshot)}function ke(e,t){return e.routeName===t.routeName&&e.className===t.className&&e.activeClassName===t.activeClassName&&e.activeStrict===t.activeStrict&&e.ignoreQueryParams===t.ignoreQueryParams&&e.onClick===t.onClick&&e.target===t.target&&e.style===t.style&&e.children===t.children&&e.hash===t.hash&&Q(e.routeParams,t.routeParams)&&Q(e.routeOptions,t.routeOptions)}const $=v(({routeName:e,routeParams:t=L,routeOptions:n=R,className:r,activeClassName:i=`active`,activeStrict:a=!1,ignoreQueryParams:o=!0,hash:s,onClick:c,target:l,children:u,...d})=>{let f=P(),p=Oe(e,t,a,o,s),m=Ce(f,e,t,s===void 0?void 0:{hash:s}),h=r=>{c&&(c(r),r.defaultPrevented)||!be(r)||l===`_blank`||(r.preventDefault(),we(f,e,t,s,n).catch(()=>{}))},g=De(p,i,r);return b(`a`,{...d,href:m,className:g,onClick:h,children:u})},ke);$.displayName=`Link`;function Ae({children:e,fallback:t,onError:n}){let r=C(P()),i=M(r.subscribe,r.getSnapshot,r.getSnapshot),s=c(n);return o(()=>{s.current=n}),a(()=>{i.error&&s.current?.(i.error,i.toRoute,i.fromRoute)},[i.version]),x(m,{children:[e,i.error?t(i.error,i.resetError):null]})}const je=()=>f(te(P()).getTree());function Me(){let e=T(P());return M(e.subscribe,e.getSnapshot,e.getSnapshot)}function Ne(e,t){let n=P(),r=c(e),i=t?.skipSameRoute??!0;o(()=>{r.current=e}),a(()=>n.subscribeLeave(({route:e,nextRoute:t,signal:n})=>{if(!(i&&e.name===t.name)&&!n.aborted)return r.current({route:e,nextRoute:t,signal:n})}),[n,i])}function Pe(e,t){let{route:n,previousRoute:r}=i(),s=c(e),l=c(null),u=t?.skipSameRoute??!0;o(()=>{s.current=e}),a(()=>{n.transition.from&&(u&&n.transition.from===n.name||l.current===n||!r||(l.current=n,s.current({route:n,previousRoute:r})))},[n,r,u])}const Fe=({router:e,children:i,announceNavigation:o,scrollRestoration:c,scrollSpy:l,viewTransitions:u})=>{a(()=>{if(!o)return;let t=V(e);return()=>{t.destroy()}},[o,e]);let f=c?.mode,p=c?.anchorScrolling,m=c?.behavior,h=c?.storageKey,g=c!==void 0;a(()=>{if(!g)return;let t=le(e,{mode:f,anchorScrolling:p,behavior:m,storageKey:h,scrollContainer:c.scrollContainer});return()=>{t.destroy()}},[e,g,f,p,m,h]);let _=l?.selector,v=l?.rootMargin,y=l!==void 0&&_!==void 0&&_!==``;a(()=>{if(!y)return;let t=_e(e,{selector:_,rootMargin:v,scrollContainer:l.scrollContainer});return()=>{t.destroy()}},[e,y,_,v]),a(()=>{if(!u)return;let t=ye(e);return()=>{t.destroy()}},[e,u]);let x=d(e),S=s(()=>ee(e),[e]),{route:C,previousRoute:w}=M(S.subscribe,S.getSnapshot,S.getSnapshot),T=s(()=>({navigator:x,route:C,previousRoute:w}),[x,C,w]);return b(t.Provider,{value:e,children:b(n.Provider,{value:x,children:b(r.Provider,{value:T,children:i})})})};export{$ as Link,n as NavigatorContext,r as RouteContext,ce as RouteView,t as RouterContext,Ae as RouterErrorBoundary,Fe as RouterProvider,N as useNavigator,i as useRoute,Pe as useRouteEnter,Ne as useRouteExit,F as useRouteNode,je as useRouteUtils,P as useRouter,Me as useRouterTransition};
2
2
  //# sourceMappingURL=index.mjs.map