UNPKG

@tanstack/solid-router

Version:

Modern and scalable routing for Solid applications

69 lines (68 loc) 5.76 kB
import { SafeFragment } from './SafeFragment.cjs'; import { AnyRouter, DeepPartial, Expand, MakeOptionalPathParams, MakeOptionalSearchParams, MakeRouteMatchUnion, MaskOptions, MatchRouteOptions, RegisteredRouter, ResolveRoute, ToSubOptionsProps } from '@tanstack/router-core'; import { JSX } from '@solidjs/web'; import * as Solid from 'solid-js'; declare module '@tanstack/router-core' { interface RouteMatchExtensions { meta?: Array<JSX.IntrinsicElements['meta'] | undefined>; links?: Array<JSX.IntrinsicElements['link'] | undefined>; scripts?: Array<JSX.IntrinsicElements['script'] | undefined>; styles?: Array<JSX.IntrinsicElements['style'] | undefined>; headScripts?: Array<JSX.IntrinsicElements['script'] | undefined>; } } /** * Select the global loading boundary for `Matches`. * * Loading UI belongs to the application, not the router. Solid 2's async * model never injects fallbacks the app didn't write: pending state * propagates through the graph to whatever boundary the app placed (or is * held at the root when there is none), and an unresolved `lazy()` chunk is * just a pending async value. The wrapper here is therefore strictly opt-in: * it renders only when the app configured root pending UI * (`pendingComponent` on the root route or `defaultPendingComponent`). * Nothing configured means no wrapper — pending match/chunk states propagate * as ordinary Solid async. * * The decision is deliberately SYMMETRIC between server and client, and * consults no hydration or environment state. Solid's hydration claims * server nodes positionally through the boundary structure, so the client * must render a boundary exactly where the server rendered one — a * client-only wrapper (even a settled one that renders its children * directly) desyncs node claiming and detaches the app from the server DOM. * The inputs below (`pendingComponent` configuration, * `disableGlobalCatchBoundary`, `router.ssr`) all resolve identically on the * server and on the hydrating client, so the trees always agree. This also * keeps the decision stable across the app's lifetime: it is made once per * `Matches` instance, so gating it on transient state (like "currently * hydrating") would permanently freeze the configured pending UI off for * every post-hydration navigation of a hydrated app. * * `router.ssr` (TanStack's `$_TSR` SSR utilities) is symmetric too: * `attachRouterServerSsrUtils` sets it on the server before rendering, and * router-core `hydrate()` (invoked by `RouterClient`, which TanStack Start * builds on) sets it on the client before rendering. It short-circuits the * wrapper exactly as before: that protocol legitimately hydrates matches in * pending states (`ssr: 'data-only'`), where a settled boundary is not * guaranteed. * * When disableGlobalCatchBoundary is true, we must NOT wrap with * Solid.Loading because Solid.Loading transforms STATUS_ERROR into * STATUS_PENDING, which prevents errors from propagating to an external * Errored boundary. */ export declare function _resolveMatchesLoadingBoundary(router: AnyRouter): typeof Solid.Loading | typeof SafeFragment; export declare function Matches(): JSX.Element; export type UseMatchRouteOptions<TRouter extends AnyRouter = RegisteredRouter, TFrom extends string = string, TTo extends string | undefined = undefined, TMaskFrom extends string = TFrom, TMaskTo extends string = ''> = ToSubOptionsProps<TRouter, TFrom, TTo> & DeepPartial<MakeOptionalSearchParams<TRouter, TFrom, TTo>> & DeepPartial<MakeOptionalPathParams<TRouter, TFrom, TTo>> & MaskOptions<TRouter, TMaskFrom, TMaskTo> & MatchRouteOptions; export declare function useMatchRoute<TRouter extends AnyRouter = RegisteredRouter>(): <const TFrom extends string = string, const TTo extends string | undefined = undefined, const TMaskFrom extends string = TFrom, const TMaskTo extends string = "">(opts: UseMatchRouteOptions<TRouter, TFrom, TTo, TMaskFrom, TMaskTo>) => Solid.Accessor<false | Expand<ResolveRoute<TRouter, TFrom, TTo>["types"]["allParams"]>>; export type MakeMatchRouteOptions<TRouter extends AnyRouter = RegisteredRouter, TFrom extends string = string, TTo extends string | undefined = undefined, TMaskFrom extends string = TFrom, TMaskTo extends string = ''> = UseMatchRouteOptions<TRouter, TFrom, TTo, TMaskFrom, TMaskTo> & { children?: ((params?: Expand<ResolveRoute<TRouter, TFrom, TTo>['types']['allParams']>) => JSX.Element) | JSX.Element; }; export declare function MatchRoute<TRouter extends AnyRouter = RegisteredRouter, const TFrom extends string = string, const TTo extends string | undefined = undefined, const TMaskFrom extends string = TFrom, const TMaskTo extends string = ''>(props: MakeMatchRouteOptions<TRouter, TFrom, TTo, TMaskFrom, TMaskTo>): any; export interface UseMatchesBaseOptions<TRouter extends AnyRouter, TSelected> { select?: (matches: Array<MakeRouteMatchUnion<TRouter>>) => TSelected; } export type UseMatchesResult<TRouter extends AnyRouter, TSelected> = unknown extends TSelected ? Array<MakeRouteMatchUnion<TRouter>> : TSelected; export declare function useMatches<TRouter extends AnyRouter = RegisteredRouter, TSelected = unknown>(opts?: UseMatchesBaseOptions<TRouter, TSelected>): Solid.Accessor<UseMatchesResult<TRouter, TSelected>>; export declare function useParentMatches<TRouter extends AnyRouter = RegisteredRouter, TSelected = unknown>(opts?: UseMatchesBaseOptions<TRouter, TSelected>): Solid.Accessor<UseMatchesResult<TRouter, TSelected>>; export declare function useChildMatches<TRouter extends AnyRouter = RegisteredRouter, TSelected = unknown>(opts?: UseMatchesBaseOptions<TRouter, TSelected>): Solid.Accessor<UseMatchesResult<TRouter, TSelected>>;