@tanstack/solid-router
Version:
Modern and scalable routing for Solid applications
69 lines (68 loc) • 5.75 kB
TypeScript
import { SafeFragment } from './SafeFragment.js';
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>>;