import type { History, Location, Path, To } from "./history"; import { Action as HistoryAction } from "./history"; import type { AgnosticDataRouteMatch, AgnosticDataRouteObject, AgnosticRouteObject, DeferredData, DetectErrorBoundaryFunction, FormEncType, HTMLFormMethod, MapRoutePropertiesFunction, RouteData, Submission, UIMatch } from "./utils"; /** * A Router instance manages all navigation and data loading/mutations */ export interface Router { /** * @internal * PRIVATE - DO NOT USE * * Return the basename for the router */ get basename(): RouterInit["basename"]; /** * @internal * PRIVATE - DO NOT USE * * Return the current state of the router */ get state(): RouterState; /** * @internal * PRIVATE - DO NOT USE * * Return the routes for this router instance */ get routes(): AgnosticDataRouteObject[]; /** * @internal * PRIVATE - DO NOT USE * * Initialize the router, including adding history listeners and kicking off * initial data fetches. Returns a function to cleanup listeners and abort * any in-progress loads */ initialize(): Router; /** * @internal * PRIVATE - DO NOT USE * * Subscribe to router.state updates * * @param fn function to call with the new state */ subscribe(fn: RouterSubscriber): () => void; /** * @internal * PRIVATE - DO NOT USE * * Enable scroll restoration behavior in the router * * @param savedScrollPositions Object that will manage positions, in case * it's being restored from sessionStorage * @param getScrollPosition Function to get the active Y scroll position * @param getKey Function to get the key to use for restoration */ enableScrollRestoration(savedScrollPositions: Record, getScrollPosition: GetScrollPositionFunction, getKey?: GetScrollRestorationKeyFunction): () => void; /** * @internal * PRIVATE - DO NOT USE * * Navigate forward/backward in the history stack * @param to Delta to move in the history stack */ navigate(to: number): Promise; /** * Navigate to the given path * @param to Path to navigate to * @param opts Navigation options (method, submission, etc.) */ navigate(to: To | null, opts?: RouterNavigateOptions): Promise; /** * @internal * PRIVATE - DO NOT USE * * Trigger a fetcher load/submission * * @param key Fetcher key * @param routeId Route that owns the fetcher * @param href href to fetch * @param opts Fetcher options, (method, submission, etc.) */ fetch(key: string, routeId: string, href: string | null, opts?: RouterFetchOptions): void; /** * @internal * PRIVATE - DO NOT USE * * Trigger a revalidation of all current route loaders and fetcher loads */ revalidate(): void; /** * @internal * PRIVATE - DO NOT USE * * Utility function to create an href for the given location * @param location */ createHref(location: Location | URL): string; /** * @internal * PRIVATE - DO NOT USE * * Utility function to URL encode a destination path according to the internal * history implementation * @param to */ encodeLocation(to: To): Path; /** * @internal * PRIVATE - DO NOT USE * * Get/create a fetcher for the given key * @param key */ getFetcher(key?: string): Fetcher; /** * @internal * PRIVATE - DO NOT USE * * Delete the fetcher for a given key * @param key */ deleteFetcher(key?: string): void; /** * @internal * PRIVATE - DO NOT USE * * Cleanup listeners and abort any in-progress loads */ dispose(): void; /** * @internal * PRIVATE - DO NOT USE * * Get a navigation blocker * @param key The identifier for the blocker * @param fn The blocker function implementation */ getBlocker(key: string, fn: BlockerFunction): Blocker; /** * @internal * PRIVATE - DO NOT USE * * Delete a navigation blocker * @param key The identifier for the blocker */ deleteBlocker(key: string): void; /** * @internal * PRIVATE - DO NOT USE * * HMR needs to pass in-flight route updates to React Router * TODO: Replace this with granular route update APIs (addRoute, updateRoute, deleteRoute) */ _internalSetRoutes(routes: AgnosticRouteObject[]): void; /** * @internal * PRIVATE - DO NOT USE * * Internal fetch AbortControllers accessed by unit tests */ _internalFetchControllers: Map; /** * @internal * PRIVATE - DO NOT USE * * Internal pending DeferredData instances accessed by unit tests */ _internalActiveDeferreds: Map; } /** * State maintained internally by the router. During a navigation, all states * reflect the the "old" location unless otherwise noted. */ export interface RouterState { /** * The action of the most recent navigation */ historyAction: HistoryAction; /** * The current location reflected by the router */ location: Location; /** * The current set of route matches */ matches: AgnosticDataRouteMatch[]; /** * Tracks whether we've completed our initial data load */ initialized: boolean; /** * Current scroll position we should start at for a new view * - number -> scroll position to restore to * - false -> do not restore scroll at all (used during submissions) * - null -> don't have a saved position, scroll to hash or top of page */ restoreScrollPosition: number | false | null; /** * Indicate whether this navigation should skip resetting the scroll position * if we are unable to restore the scroll position */ preventScrollReset: boolean; /** * Tracks the state of the current navigation */ navigation: Navigation; /** * Tracks any in-progress revalidations */ revalidation: RevalidationState; /** * Data from the loaders for the current matches */ loaderData: RouteData; /** * Data from the action for the current matches */ actionData: RouteData | null; /** * Errors caught from loaders for the current matches */ errors: RouteData | null; /** * Map of current fetchers */ fetchers: Map; /** * Map of current blockers */ blockers: Map; } /** * Data that can be passed into hydrate a Router from SSR */ export type HydrationState = Partial>; /** * Future flags to toggle new feature behavior */ export interface FutureConfig { v7_normalizeFormMethod: boolean; v7_prependBasename: boolean; } /** * Initialization options for createRouter */ export interface RouterInit { routes: AgnosticRouteObject[]; history: History; basename?: string; /** * @deprecated Use `mapRouteProperties` instead */ detectErrorBoundary?: DetectErrorBoundaryFunction; mapRouteProperties?: MapRoutePropertiesFunction; future?: Partial; hydrationData?: HydrationState; window?: Window; } /** * State returned from a server-side query() call */ export interface StaticHandlerContext { basename: Router["basename"]; location: RouterState["location"]; matches: RouterState["matches"]; loaderData: RouterState["loaderData"]; actionData: RouterState["actionData"]; errors: RouterState["errors"]; statusCode: number; loaderHeaders: Record; actionHeaders: Record; activeDeferreds: Record | null; _deepestRenderedBoundaryId?: string | null; } /** * A StaticHandler instance manages a singular SSR navigation/fetch event */ export interface StaticHandler { dataRoutes: AgnosticDataRouteObject[]; query(request: Request, opts?: { requestContext?: unknown; }): Promise; queryRoute(request: Request, opts?: { routeId?: string; requestContext?: unknown; }): Promise; } /** * Subscriber function signature for changes to router state */ export interface RouterSubscriber { (state: RouterState): void; } /** * Function signature for determining the key to be used in scroll restoration * for a given location */ export interface GetScrollRestorationKeyFunction { (location: Location, matches: UIMatch[]): string | null; } /** * Function signature for determining the current scroll position */ export interface GetScrollPositionFunction { (): number; } export type RelativeRoutingType = "route" | "path"; type BaseNavigateOrFetchOptions = { preventScrollReset?: boolean; relative?: RelativeRoutingType; }; type BaseNavigateOptions = BaseNavigateOrFetchOptions & { replace?: boolean; state?: any; fromRouteId?: string; }; type BaseSubmissionOptions = { formMethod?: HTMLFormMethod; formEncType?: FormEncType; } & ({ formData: FormData; body?: undefined; } | { formData?: undefined; body: any; }); /** * Options for a navigate() call for a normal (non-submission) navigation */ type LinkNavigateOptions = BaseNavigateOptions; /** * Options for a navigate() call for a submission navigation */ type SubmissionNavigateOptions = BaseNavigateOptions & BaseSubmissionOptions; /** * Options to pass to navigate() for a navigation */ export type RouterNavigateOptions = LinkNavigateOptions | SubmissionNavigateOptions; /** * Options for a fetch() load */ type LoadFetchOptions = BaseNavigateOrFetchOptions; /** * Options for a fetch() submission */ type SubmitFetchOptions = BaseNavigateOrFetchOptions & BaseSubmissionOptions; /** * Options to pass to fetch() */ export type RouterFetchOptions = LoadFetchOptions | SubmitFetchOptions; /** * Potential states for state.navigation */ export type NavigationStates = { Idle: { state: "idle"; location: undefined; formMethod: undefined; formAction: undefined; formEncType: undefined; formData: undefined; json: undefined; text: undefined; }; Loading: { state: "loading"; location: Location; formMethod: Submission["formMethod"] | undefined; formAction: Submission["formAction"] | undefined; formEncType: Submission["formEncType"] | undefined; formData: Submission["formData"] | undefined; json: Submission["json"] | undefined; text: Submission["text"] | undefined; }; Submitting: { state: "submitting"; location: Location; formMethod: Submission["formMethod"]; formAction: Submission["formAction"]; formEncType: Submission["formEncType"]; formData: Submission["formData"]; json: Submission["json"]; text: Submission["text"]; }; }; export type Navigation = NavigationStates[keyof NavigationStates]; export type RevalidationState = "idle" | "loading"; /** * Potential states for fetchers */ type FetcherStates = { Idle: { state: "idle"; formMethod: undefined; formAction: undefined; formEncType: undefined; text: undefined; formData: undefined; json: undefined; data: TData | undefined; }; Loading: { state: "loading"; formMethod: Submission["formMethod"] | undefined; formAction: Submission["formAction"] | undefined; formEncType: Submission["formEncType"] | undefined; text: Submission["text"] | undefined; formData: Submission["formData"] | undefined; json: Submission["json"] | undefined; data: TData | undefined; }; Submitting: { state: "submitting"; formMethod: Submission["formMethod"]; formAction: Submission["formAction"]; formEncType: Submission["formEncType"]; text: Submission["text"]; formData: Submission["formData"]; json: Submission["json"]; data: TData | undefined; }; }; export type Fetcher = FetcherStates[keyof FetcherStates]; interface BlockerBlocked { state: "blocked"; reset(): void; proceed(): void; location: Location; } interface BlockerUnblocked { state: "unblocked"; reset: undefined; proceed: undefined; location: undefined; } interface BlockerProceeding { state: "proceeding"; reset: undefined; proceed: undefined; location: Location; } export type Blocker = BlockerUnblocked | BlockerBlocked | BlockerProceeding; export type BlockerFunction = (args: { currentLocation: Location; nextLocation: Location; historyAction: HistoryAction; }) => boolean; export declare const IDLE_NAVIGATION: NavigationStates["Idle"]; export declare const IDLE_FETCHER: FetcherStates["Idle"]; export declare const IDLE_BLOCKER: BlockerUnblocked; /** * Create a router and listen to history POP navigations */ export declare function createRouter(init: RouterInit): Router; export declare const UNSAFE_DEFERRED_SYMBOL: unique symbol; export interface CreateStaticHandlerOptions { basename?: string; /** * @deprecated Use `mapRouteProperties` instead */ detectErrorBoundary?: DetectErrorBoundaryFunction; mapRouteProperties?: MapRoutePropertiesFunction; } export declare function createStaticHandler(routes: AgnosticRouteObject[], opts?: CreateStaticHandlerOptions): StaticHandler; /** * Given an existing StaticHandlerContext and an error thrown at render time, * provide an updated StaticHandlerContext suitable for a second SSR render */ export declare function getStaticContextFromError(routes: AgnosticDataRouteObject[], context: StaticHandlerContext, error: any): StaticHandlerContext; export declare function isDeferredData(value: any): value is DeferredData; export {};