import type { MountRouterOptions, RenderProps, RouterState } from "@nifrajs/web" // `/client`, not the root: the root's graph carries the server, and Vite's dev server evaluates it // instead of tree-shaking it - which broke hydration before the browser ran a line of app code. import { searchOfChain } from "@nifrajs/web/client" /** The client half of the server's `RenderProps`, so the first render matches the SSR markup. */ export function routeProps( state: RouterState, searchSchemas: MountRouterOptions["searchSchemas"], matchChains?: MountRouterOptions["matchChains"], ): RenderProps { const matchChain = matchChains?.[state.routeId] // Derive this route's typed `search` from the URL query + the route's schema CHAIN (layout schemas + // page, merged page-wins), the SAME `searchOfChain` the server ran, so `useSearch` reads an identical // value and hydrates with no drift. const q = state.path.indexOf("?") const rawSearch = q === -1 ? "" : state.path.slice(q) return { data: state.data, ...(state.serverComponents === undefined ? {} : { serverComponents: state.serverComponents }), // Each layout's own loader data. Without it a layout renders `data: null` on the client while the // server rendered it with its data - a hydration mismatch on the first paint. ...(state.layoutData !== undefined ? { layoutData: state.layoutData } : {}), actionData: state.actionData, pending: state.pending, ...(state.pendingPath !== undefined ? { pendingPath: state.pendingPath } : {}), // `params`/`path` feed the routing hooks (useParams/useLocation) via compose's RouterContext - // sourced from router state here, matching the SSR render's request-derived values on hydration. params: state.params, path: state.path, search: searchOfChain(searchSchemas?.[state.routeId] ?? [], rawSearch), // The in-flight submission (for optimistic UI) - spread only when present. ...(state.submission ? { submission: state.submission } : {}), ...(state.boundaries !== undefined ? { boundaries: state.boundaries } : {}), // The chain `useMatches` reports - the server passed the same one to the SSR render. ...(matchChain !== undefined ? { matchChain } : {}), } }