UNPKG

@tanstack/react-router

Version:

Modern and scalable routing for React applications

549 lines (507 loc) 13.3 kB
import { BaseRootRoute, BaseRoute, BaseRouteApi, notFound, } from '@tanstack/router-core' import { useLoaderData } from './useLoaderData' import { useLoaderDeps } from './useLoaderDeps' import { useParams } from './useParams' import { useSearch } from './useSearch' import { useNavigate } from './useNavigate' import { useMatch } from './useMatch' import { useRouter } from './useRouter' import type { AnyContext, AnyRoute, AnyRouter, ConstrainLiteral, ErrorComponentProps, NotFoundError, NotFoundRouteProps, RegisteredRouter, ResolveFullPath, ResolveId, ResolveParams, RootRouteId, RootRouteOptions, RouteConstraints, RouteIds, RouteMask, RouteOptions, RouteTypesById, RouterCore, ToMaskOptions, UseNavigateResult, } from '@tanstack/router-core' import type { UseLoaderDataRoute } from './useLoaderData' import type { UseMatchRoute } from './useMatch' import type { UseLoaderDepsRoute } from './useLoaderDeps' import type { UseParamsRoute } from './useParams' import type { UseSearchRoute } from './useSearch' import type * as React from 'react' import type { UseRouteContextRoute } from './useRouteContext' declare module '@tanstack/router-core' { export interface UpdatableRouteOptionsExtensions { component?: RouteComponent errorComponent?: false | null | ErrorRouteComponent notFoundComponent?: NotFoundRouteComponent pendingComponent?: RouteComponent } export interface RouteExtensions< TId extends string, TFullPath extends string, > { useMatch: UseMatchRoute<TId> useRouteContext: UseRouteContextRoute<TId> useSearch: UseSearchRoute<TId> useParams: UseParamsRoute<TId> useLoaderDeps: UseLoaderDepsRoute<TId> useLoaderData: UseLoaderDataRoute<TId> useNavigate: () => UseNavigateResult<TFullPath> } } export function getRouteApi< const TId, TRouter extends AnyRouter = RegisteredRouter, >(id: ConstrainLiteral<TId, RouteIds<TRouter['routeTree']>>) { return new RouteApi<TId, TRouter>({ id }) } export class RouteApi< TId, TRouter extends AnyRouter = RegisteredRouter, > extends BaseRouteApi<TId, TRouter> { /** * @deprecated Use the `getRouteApi` function instead. */ constructor({ id }: { id: TId }) { super({ id }) } useMatch: UseMatchRoute<TId> = (opts) => { return useMatch({ select: opts?.select, from: this.id, structuralSharing: opts?.structuralSharing, } as any) as any } useRouteContext: UseRouteContextRoute<TId> = (opts) => { return useMatch({ from: this.id as any, select: (d) => (opts?.select ? opts.select(d.context) : d.context), }) as any } useSearch: UseSearchRoute<TId> = (opts) => { // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion return useSearch({ select: opts?.select, structuralSharing: opts?.structuralSharing, from: this.id, } as any) as any } useParams: UseParamsRoute<TId> = (opts) => { // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion return useParams({ select: opts?.select, structuralSharing: opts?.structuralSharing, from: this.id, } as any) as any } useLoaderDeps: UseLoaderDepsRoute<TId> = (opts) => { return useLoaderDeps({ ...opts, from: this.id, strict: false } as any) } useLoaderData: UseLoaderDataRoute<TId> = (opts) => { return useLoaderData({ ...opts, from: this.id, strict: false } as any) } useNavigate = (): UseNavigateResult< RouteTypesById<TRouter, TId>['fullPath'] > => { const router = useRouter() return useNavigate({ from: router.routesById[this.id as string].fullPath }) } notFound = (opts?: NotFoundError) => { return notFound({ routeId: this.id as string, ...opts }) } } export class Route< in out TParentRoute extends RouteConstraints['TParentRoute'] = AnyRoute, in out TPath extends RouteConstraints['TPath'] = '/', in out TFullPath extends RouteConstraints['TFullPath'] = ResolveFullPath< TParentRoute, TPath >, in out TCustomId extends RouteConstraints['TCustomId'] = string, in out TId extends RouteConstraints['TId'] = ResolveId< TParentRoute, TCustomId, TPath >, in out TSearchValidator = undefined, in out TParams = ResolveParams<TPath>, in out TRouterContext = AnyContext, in out TRouteContextFn = AnyContext, in out TBeforeLoadFn = AnyContext, in out TLoaderDeps extends Record<string, any> = {}, in out TLoaderFn = undefined, in out TChildren = unknown, in out TFileRouteTypes = unknown, > extends BaseRoute< TParentRoute, TPath, TFullPath, TCustomId, TId, TSearchValidator, TParams, TRouterContext, TRouteContextFn, TBeforeLoadFn, TLoaderDeps, TLoaderFn, TChildren, TFileRouteTypes > { /** * @deprecated Use the `createRoute` function instead. */ constructor( options?: RouteOptions< TParentRoute, TId, TCustomId, TFullPath, TPath, TSearchValidator, TParams, TLoaderDeps, TLoaderFn, TRouterContext, TRouteContextFn, TBeforeLoadFn >, ) { super(options) ;(this as any).$$typeof = Symbol.for('react.memo') } useMatch: UseMatchRoute<TId> = (opts) => { return useMatch({ select: opts?.select, from: this.id, structuralSharing: opts?.structuralSharing, } as any) as any } useRouteContext: UseRouteContextRoute<TId> = (opts?) => { return useMatch({ ...opts, from: this.id, select: (d) => (opts?.select ? opts.select(d.context) : d.context), }) as any } useSearch: UseSearchRoute<TId> = (opts) => { // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion return useSearch({ select: opts?.select, structuralSharing: opts?.structuralSharing, from: this.id, } as any) as any } useParams: UseParamsRoute<TId> = (opts) => { // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion return useParams({ select: opts?.select, structuralSharing: opts?.structuralSharing, from: this.id, } as any) as any } useLoaderDeps: UseLoaderDepsRoute<TId> = (opts) => { return useLoaderDeps({ ...opts, from: this.id } as any) } useLoaderData: UseLoaderDataRoute<TId> = (opts) => { return useLoaderData({ ...opts, from: this.id } as any) } useNavigate = (): UseNavigateResult<TFullPath> => { return useNavigate({ from: this.fullPath }) } } export function createRoute< TParentRoute extends RouteConstraints['TParentRoute'] = AnyRoute, TPath extends RouteConstraints['TPath'] = '/', TFullPath extends RouteConstraints['TFullPath'] = ResolveFullPath< TParentRoute, TPath >, TCustomId extends RouteConstraints['TCustomId'] = string, TId extends RouteConstraints['TId'] = ResolveId< TParentRoute, TCustomId, TPath >, TSearchValidator = undefined, TParams = ResolveParams<TPath>, TRouteContextFn = AnyContext, TBeforeLoadFn = AnyContext, TLoaderDeps extends Record<string, any> = {}, TLoaderFn = undefined, TChildren = unknown, >( options: RouteOptions< TParentRoute, TId, TCustomId, TFullPath, TPath, TSearchValidator, TParams, TLoaderDeps, TLoaderFn, AnyContext, TRouteContextFn, TBeforeLoadFn >, ): Route< TParentRoute, TPath, TFullPath, TCustomId, TId, TSearchValidator, TParams, AnyContext, TRouteContextFn, TBeforeLoadFn, TLoaderDeps, TLoaderFn, TChildren > { return new Route< TParentRoute, TPath, TFullPath, TCustomId, TId, TSearchValidator, TParams, AnyContext, TRouteContextFn, TBeforeLoadFn, TLoaderDeps, TLoaderFn, TChildren >(options) } export type AnyRootRoute = RootRoute<any, any, any, any, any, any, any, any> export function createRootRouteWithContext<TRouterContext extends {}>() { return < TRouteContextFn = AnyContext, TBeforeLoadFn = AnyContext, TSearchValidator = undefined, TLoaderDeps extends Record<string, any> = {}, TLoaderFn = undefined, >( options?: RootRouteOptions< TSearchValidator, TRouterContext, TRouteContextFn, TBeforeLoadFn, TLoaderDeps, TLoaderFn >, ) => { return createRootRoute< TSearchValidator, TRouterContext, TRouteContextFn, TBeforeLoadFn, TLoaderDeps, TLoaderFn >(options as any) } } /** * @deprecated Use the `createRootRouteWithContext` function instead. */ export const rootRouteWithContext = createRootRouteWithContext export class RootRoute< in out TSearchValidator = undefined, in out TRouterContext = {}, in out TRouteContextFn = AnyContext, in out TBeforeLoadFn = AnyContext, in out TLoaderDeps extends Record<string, any> = {}, in out TLoaderFn = undefined, in out TChildren = unknown, in out TFileRouteTypes = unknown, > extends BaseRootRoute< TSearchValidator, TRouterContext, TRouteContextFn, TBeforeLoadFn, TLoaderDeps, TLoaderFn, TChildren, TFileRouteTypes > { /** * @deprecated `RootRoute` is now an internal implementation detail. Use `createRootRoute()` instead. */ constructor( options?: RootRouteOptions< TSearchValidator, TRouterContext, TRouteContextFn, TBeforeLoadFn, TLoaderDeps, TLoaderFn >, ) { super(options) ;(this as any).$$typeof = Symbol.for('react.memo') } useMatch: UseMatchRoute<RootRouteId> = (opts) => { return useMatch({ select: opts?.select, from: this.id, structuralSharing: opts?.structuralSharing, } as any) as any } useRouteContext: UseRouteContextRoute<RootRouteId> = (opts) => { return useMatch({ ...opts, from: this.id, select: (d) => (opts?.select ? opts.select(d.context) : d.context), }) as any } useSearch: UseSearchRoute<RootRouteId> = (opts) => { // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion return useSearch({ select: opts?.select, structuralSharing: opts?.structuralSharing, from: this.id, } as any) as any } useParams: UseParamsRoute<RootRouteId> = (opts) => { // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion return useParams({ select: opts?.select, structuralSharing: opts?.structuralSharing, from: this.id, } as any) as any } useLoaderDeps: UseLoaderDepsRoute<RootRouteId> = (opts) => { return useLoaderDeps({ ...opts, from: this.id } as any) } useLoaderData: UseLoaderDataRoute<RootRouteId> = (opts) => { return useLoaderData({ ...opts, from: this.id } as any) } useNavigate = (): UseNavigateResult<'/'> => { return useNavigate({ from: this.fullPath }) } } export function createRootRoute< TSearchValidator = undefined, TRouterContext = {}, TRouteContextFn = AnyContext, TBeforeLoadFn = AnyContext, TLoaderDeps extends Record<string, any> = {}, TLoaderFn = undefined, >( options?: RootRouteOptions< TSearchValidator, TRouterContext, TRouteContextFn, TBeforeLoadFn, TLoaderDeps, TLoaderFn >, ): RootRoute< TSearchValidator, TRouterContext, TRouteContextFn, TBeforeLoadFn, TLoaderDeps, TLoaderFn, unknown, unknown > { return new RootRoute< TSearchValidator, TRouterContext, TRouteContextFn, TBeforeLoadFn, TLoaderDeps, TLoaderFn >(options) } export function createRouteMask< TRouteTree extends AnyRoute, TFrom extends string, TTo extends string, >( opts: { routeTree: TRouteTree } & ToMaskOptions<RouterCore<TRouteTree, 'never', boolean>, TFrom, TTo>, ): RouteMask<TRouteTree> { return opts as any } export type ReactNode = any export type SyncRouteComponent<TProps> = | ((props: TProps) => ReactNode) | React.LazyExoticComponent<(props: TProps) => ReactNode> export type AsyncRouteComponent<TProps> = SyncRouteComponent<TProps> & { preload?: () => Promise<void> } export type RouteComponent<TProps = any> = AsyncRouteComponent<TProps> export type ErrorRouteComponent = RouteComponent<ErrorComponentProps> export type NotFoundRouteComponent = SyncRouteComponent<NotFoundRouteProps> export class NotFoundRoute< TParentRoute extends AnyRootRoute, TRouterContext = AnyContext, TRouteContextFn = AnyContext, TBeforeLoadFn = AnyContext, TSearchValidator = undefined, TLoaderDeps extends Record<string, any> = {}, TLoaderFn = undefined, TChildren = unknown, > extends Route< TParentRoute, '/404', '/404', '404', '404', TSearchValidator, {}, TRouterContext, TRouteContextFn, TBeforeLoadFn, TLoaderDeps, TLoaderFn, TChildren > { constructor( options: Omit< RouteOptions< TParentRoute, string, string, string, string, TSearchValidator, {}, TLoaderDeps, TLoaderFn, TRouterContext, TRouteContextFn, TBeforeLoadFn >, | 'caseSensitive' | 'parseParams' | 'stringifyParams' | 'path' | 'id' | 'params' >, ) { super({ ...(options as any), id: '404', }) } }