UNPKG

20.6 kBTypeScriptView Raw
1
2import { Action, History, Location, Path, To } from "./history.js";
3import { DataRouteMatch, DataRouteObject, DataStrategyFunction, FormEncType, HTMLFormMethod, MapRoutePropertiesFunction, MaybePromise, PatchRoutesOnNavigationFunction, RouteData, RouteManifest, RouteObject, RouterContextProvider, Submission, UIMatch } from "./utils.js";
4import { ClientInstrumentation, ServerInstrumentation } from "./instrumentation.js";
5
6//#region lib/router/router.d.ts
7/**
8 * A Router instance manages all navigation and data loading/mutations
9 */
10interface Router {
11 /**
12 * @private
13 * PRIVATE - DO NOT USE
14 *
15 * Return the basename for the router
16 */
17 get basename(): RouterInit["basename"];
18 /**
19 * @private
20 * PRIVATE - DO NOT USE
21 *
22 * Return the future config for the router
23 */
24 get future(): FutureConfig;
25 /**
26 * @private
27 * PRIVATE - DO NOT USE
28 *
29 * Return the current state of the router
30 */
31 get state(): RouterState;
32 /**
33 * @private
34 * PRIVATE - DO NOT USE
35 *
36 * Return the routes for this router instance
37 */
38 get routes(): DataRouteObject[];
39 /**
40 * @private
41 * PRIVATE - DO NOT USE
42 *
43 * Match routes against a location using the router's configured route
44 * matching implementation.
45 */
46 match(locationArg: Partial<Location> | string): DataRouteMatch[] | null;
47 /**
48 * @private
49 * PRIVATE - DO NOT USE
50 *
51 * Return the manifest for this router instance
52 */
53 get manifest(): RouteManifest;
54 /**
55 * @private
56 * PRIVATE - DO NOT USE
57 *
58 * Return the window associated with the router
59 */
60 get window(): RouterInit["window"];
61 /**
62 * @private
63 * PRIVATE - DO NOT USE
64 *
65 * Initialize the router, including adding history listeners and kicking off
66 * initial data fetches. Returns a function to cleanup listeners and abort
67 * any in-progress loads
68 */
69 initialize(): Router;
70 /**
71 * @private
72 * PRIVATE - DO NOT USE
73 *
74 * Subscribe to router.state updates
75 *
76 * @param fn function to call with the new state
77 */
78 subscribe(fn: RouterSubscriber): () => void;
79 /**
80 * @private
81 * PRIVATE - DO NOT USE
82 *
83 * Enable scroll restoration behavior in the router
84 *
85 * @param savedScrollPositions Object that will manage positions, in case
86 * it's being restored from sessionStorage
87 * @param getScrollPosition Function to get the active Y scroll position
88 * @param getKey Function to get the key to use for restoration
89 */
90 enableScrollRestoration(savedScrollPositions: Record<string, number>, getScrollPosition: GetScrollPositionFunction, getKey?: GetScrollRestorationKeyFunction): () => void;
91 /**
92 * @private
93 * PRIVATE - DO NOT USE
94 *
95 * Navigate forward/backward in the history stack
96 * @param to Delta to move in the history stack
97 */
98 navigate(to: number): Promise<void>;
99 /**
100 * Navigate to the given path
101 * @param to Path to navigate to
102 * @param opts Navigation options (method, submission, etc.)
103 */
104 navigate(to: To | null, opts?: RouterNavigateOptions): Promise<void>;
105 /**
106 * @private
107 * PRIVATE - DO NOT USE
108 *
109 * Trigger a fetcher load/submission
110 *
111 * @param key Fetcher key
112 * @param routeId Route that owns the fetcher
113 * @param href href to fetch
114 * @param opts Fetcher options, (method, submission, etc.)
115 */
116 fetch(key: string, routeId: string, href: string | null, opts?: RouterFetchOptions): Promise<void>;
117 /**
118 * @private
119 * PRIVATE - DO NOT USE
120 *
121 * Trigger a revalidation of all current route loaders and fetcher loads
122 */
123 revalidate(): Promise<void>;
124 /**
125 * @private
126 * PRIVATE - DO NOT USE
127 *
128 * Utility function to create an href for the given location
129 * @param location
130 */
131 createHref(location: Location | URL): string;
132 /**
133 * @private
134 * PRIVATE - DO NOT USE
135 *
136 * Utility function to create a URL for the given location
137 * @param location
138 */
139 createURL?(to: To): URL;
140 /**
141 * @private
142 * PRIVATE - DO NOT USE
143 *
144 * Utility function to URL encode a destination path according to the internal
145 * history implementation
146 * @param to
147 */
148 encodeLocation(to: To): Path;
149 /**
150 * @private
151 * PRIVATE - DO NOT USE
152 *
153 * Get/create a fetcher for the given key
154 * @param key
155 */
156 getFetcher<TData = any>(key: string): Fetcher<TData>;
157 /**
158 * @internal
159 * PRIVATE - DO NOT USE
160 *
161 * Reset the fetcher for a given key
162 * @param key
163 */
164 resetFetcher(key: string, opts?: {
165 reason?: unknown;
166 }): void;
167 /**
168 * @private
169 * PRIVATE - DO NOT USE
170 *
171 * Delete the fetcher for a given key
172 * @param key
173 */
174 deleteFetcher(key: string): void;
175 /**
176 * @private
177 * PRIVATE - DO NOT USE
178 *
179 * Cleanup listeners and abort any in-progress loads
180 */
181 dispose(): void;
182 /**
183 * @private
184 * PRIVATE - DO NOT USE
185 *
186 * Get a navigation blocker
187 * @param key The identifier for the blocker
188 * @param fn The blocker function implementation
189 */
190 getBlocker(key: string, fn: BlockerFunction): Blocker;
191 /**
192 * @private
193 * PRIVATE - DO NOT USE
194 *
195 * Delete a navigation blocker
196 * @param key The identifier for the blocker
197 */
198 deleteBlocker(key: string): void;
199 /**
200 * @private
201 * PRIVATE DO NOT USE
202 *
203 * Patch additional children routes into an existing parent route
204 * @param routeId The parent route id or a callback function accepting `patch`
205 * to perform batch patching
206 * @param children The additional children routes
207 * @param unstable_allowElementMutations Allow mutation or route elements on
208 * existing routes. Intended for RSC-usage
209 * only.
210 */
211 patchRoutes(routeId: string | null, children: RouteObject[], unstable_allowElementMutations?: boolean): void;
212 /**
213 * @private
214 * PRIVATE - DO NOT USE
215 *
216 * HMR needs to pass in-flight route updates to React Router
217 * TODO: Replace this with granular route update APIs (addRoute, updateRoute, deleteRoute)
218 */
219 _internalSetRoutes(routes: RouteObject[]): void;
220 /**
221 * @private
222 * PRIVATE - DO NOT USE
223 *
224 * Cause subscribers to re-render. This is used to force a re-render.
225 */
226 _internalSetStateDoNotUseOrYouWillBreakYourApp(state: Partial<RouterState>): void;
227 /**
228 * @private
229 * PRIVATE - DO NOT USE
230 *
231 * Internal fetch AbortControllers accessed by unit tests
232 */
233 _internalFetchControllers: Map<string, AbortController>;
234}
235/**
236 * State maintained internally by the router. During a navigation, all states
237 * reflect the "old" location unless otherwise noted.
238 */
239interface RouterState {
240 /**
241 * The action of the most recent navigation
242 */
243 historyAction: Action;
244 /**
245 * The current location reflected by the router
246 */
247 location: Location;
248 /**
249 * The current set of route matches
250 */
251 matches: DataRouteMatch[];
252 /**
253 * Tracks whether we've completed our initial data load
254 */
255 initialized: boolean;
256 /**
257 * Tracks whether we should be rendering a HydrateFallback during hydration
258 */
259 renderFallback: boolean;
260 /**
261 * Current scroll position we should start at for a new view
262 * - number -> scroll position to restore to
263 * - false -> do not restore scroll at all (used during submissions/revalidations)
264 * - null -> don't have a saved position, scroll to hash or top of page
265 */
266 restoreScrollPosition: number | false | null;
267 /**
268 * Indicate whether this navigation should skip resetting the scroll position
269 * if we are unable to restore the scroll position
270 */
271 preventScrollReset: boolean;
272 /**
273 * Tracks the state of the current navigation
274 */
275 navigation: Navigation;
276 /**
277 * Tracks any in-progress revalidations
278 */
279 revalidation: RevalidationState;
280 /**
281 * Data from the loaders for the current matches
282 */
283 loaderData: RouteData;
284 /**
285 * Data from the action for the current matches
286 */
287 actionData: RouteData | null;
288 /**
289 * Errors caught from loaders for the current matches
290 */
291 errors: RouteData | null;
292 /**
293 * Map of current fetchers
294 */
295 fetchers: Map<string, Fetcher>;
296 /**
297 * Map of current blockers
298 */
299 blockers: Map<string, Blocker>;
300}
301/**
302 * Data that can be passed into hydrate a Router from SSR
303 */
304type HydrationState = Partial<Pick<RouterState, "loaderData" | "actionData" | "errors">>;
305/**
306 * Future flags to toggle new feature behavior
307 */
308interface FutureConfig {
309 /** Enables route-pattern matching after calling `unstable_preloadRoutePattern()`. */
310 unstable_routePatternMatching?: boolean;
311}
312/**
313 * Initialization options for createRouter
314 */
315interface RouterInit {
316 routes: RouteObject[];
317 history: History;
318 basename?: string;
319 getContext?: () => MaybePromise<RouterContextProvider>;
320 instrumentations?: ClientInstrumentation[];
321 mapRouteProperties?: MapRoutePropertiesFunction;
322 future?: Partial<FutureConfig>;
323 hydrationRouteProperties?: string[];
324 hydrationData?: HydrationState;
325 window?: Window;
326 dataStrategy?: DataStrategyFunction;
327 patchRoutesOnNavigation?: PatchRoutesOnNavigationFunction;
328}
329/**
330 * State returned from a server-side query() call
331 */
332interface StaticHandlerContext {
333 basename: Router["basename"];
334 location: RouterState["location"];
335 matches: RouterState["matches"];
336 loaderData: RouterState["loaderData"];
337 actionData: RouterState["actionData"];
338 errors: RouterState["errors"];
339 statusCode: number;
340 loaderHeaders: Record<string, Headers>;
341 actionHeaders: Record<string, Headers>;
342 _deepestRenderedBoundaryId?: string | null;
343 /** @private */
344 _match: StaticHandler["match"];
345}
346/**
347 * A StaticHandler instance manages a singular SSR navigation/fetch event
348 */
349interface StaticHandler {
350 /**
351 * The set of data routes managed by this handler
352 */
353 dataRoutes: DataRouteObject[];
354 /**
355 * @private
356 * PRIVATE - DO NOT USE
357 *
358 * Match routes against a location using the handler's configured route
359 * matching implementation.
360 */
361 match(locationArg: Partial<Location> | string): DataRouteMatch[] | null;
362 /**
363 * Perform a query for a given request - executing all matched route
364 * loaders/actions. Used for document requests.
365 *
366 * @param request The request to query
367 * @param opts Optional query options
368 * @param opts.dataStrategy Alternate dataStrategy implementation
369 * @param opts.filterMatchesToLoad Predicate function to filter which matches should be loaded
370 * @param opts.generateMiddlewareResponse To enable middleware, provide a function
371 * to generate a response to bubble back up the middleware chain
372 * @param opts.requestContext Context object to pass to loaders/actions
373 * @param opts.skipLoaderErrorBubbling Skip loader error bubbling
374 * @param opts.skipRevalidation Skip revalidation after action submission
375 * @param opts.normalizePath Normalize the request path
376 */
377 query(request: Request, opts?: {
378 requestContext?: unknown;
379 filterMatchesToLoad?: (match: DataRouteMatch) => boolean;
380 skipLoaderErrorBubbling?: boolean;
381 skipRevalidation?: boolean;
382 dataStrategy?: DataStrategyFunction<unknown>;
383 generateMiddlewareResponse?: (query: (r: Request, args?: {
384 filterMatchesToLoad?: (match: DataRouteMatch) => boolean;
385 }) => Promise<StaticHandlerContext | Response>) => MaybePromise<Response>;
386 normalizePath?: (request: Request) => Path;
387 }): Promise<StaticHandlerContext | Response>;
388 /**
389 * Perform a query for a specific route. Used for resource requests.
390 *
391 * @param request The request to query
392 * @param opts Optional queryRoute options
393 * @param opts.dataStrategy Alternate dataStrategy implementation
394 * @param opts.generateMiddlewareResponse To enable middleware, provide a function
395 * to generate a response to bubble back up the middleware chain
396 * @param opts.requestContext Context object to pass to loaders/actions
397 * @param opts.routeId The ID of the route to query
398 * @param opts.normalizePath Normalize the request path
399 */
400 queryRoute(request: Request, opts?: {
401 routeId?: string;
402 requestContext?: unknown;
403 dataStrategy?: DataStrategyFunction<unknown>;
404 generateMiddlewareResponse?: (queryRoute: (r: Request) => Promise<Response>) => MaybePromise<Response>;
405 normalizePath?: (request: Request) => Path;
406 }): Promise<any>;
407}
408type ViewTransitionOpts = {
409 currentLocation: Location;
410 nextLocation: Location;
411};
412/**
413 * Subscriber function signature for changes to router state
414 */
415interface RouterSubscriber {
416 (state: RouterState, opts: {
417 deletedFetchers: string[];
418 newErrors: RouteData | null;
419 viewTransitionOpts?: ViewTransitionOpts;
420 flushSync: boolean;
421 }): void;
422}
423/**
424 * Function signature for determining the key to be used in scroll restoration
425 * for a given location
426 */
427interface GetScrollRestorationKeyFunction {
428 (location: Location, matches: UIMatch[]): string | null;
429}
430/**
431 * Function signature for determining the current scroll position
432 */
433interface GetScrollPositionFunction {
434 (): number;
435}
436/**
437 * - "route": relative to the route hierarchy so `..` means remove all segments
438 * of the current route even if it has many. For example, a `route("posts/:id")`
439 * would have both `:id` and `posts` removed from the url.
440 * - "path": relative to the pathname so `..` means remove one segment of the
441 * pathname. For example, a `route("posts/:id")` would have only `:id` removed
442 * from the url.
443 */
444type RelativeRoutingType = "route" | "path";
445type BaseNavigateOrFetchOptions = {
446 preventScrollReset?: boolean;
447 relative?: RelativeRoutingType;
448 flushSync?: boolean;
449 defaultShouldRevalidate?: boolean;
450};
451type BaseNavigateOptions = BaseNavigateOrFetchOptions & {
452 replace?: boolean;
453 state?: any;
454 fromRouteId?: string;
455 viewTransition?: boolean;
456 mask?: To;
457};
458type BaseSubmissionOptions = {
459 formMethod?: HTMLFormMethod;
460 formEncType?: FormEncType;
461} & ({
462 formData: FormData;
463 body?: undefined;
464} | {
465 formData?: undefined;
466 body: any;
467});
468/**
469 * Options for a navigate() call for a normal (non-submission) navigation
470 */
471type LinkNavigateOptions = BaseNavigateOptions;
472/**
473 * Options for a navigate() call for a submission navigation
474 */
475type SubmissionNavigateOptions = BaseNavigateOptions & BaseSubmissionOptions;
476/**
477 * Options to pass to navigate() for a navigation
478 */
479type RouterNavigateOptions = LinkNavigateOptions | SubmissionNavigateOptions;
480/**
481 * Options for a fetch() load
482 */
483type LoadFetchOptions = BaseNavigateOrFetchOptions;
484/**
485 * Options for a fetch() submission
486 */
487type SubmitFetchOptions = BaseNavigateOrFetchOptions & BaseSubmissionOptions;
488/**
489 * Options to pass to fetch()
490 */
491type RouterFetchOptions = LoadFetchOptions | SubmitFetchOptions;
492/**
493 * Potential states for state.navigation
494 */
495type NavigationStates = {
496 Idle: {
497 state: "idle";
498 location: undefined;
499 matches: undefined;
500 historyAction: undefined;
501 formMethod: undefined;
502 formAction: undefined;
503 formEncType: undefined;
504 formData: undefined;
505 json: undefined;
506 text: undefined;
507 };
508 Loading: {
509 state: "loading";
510 location: Location;
511 matches: DataRouteMatch[];
512 historyAction: Action;
513 formMethod: Submission["formMethod"] | undefined;
514 formAction: Submission["formAction"] | undefined;
515 formEncType: Submission["formEncType"] | undefined;
516 formData: Submission["formData"] | undefined;
517 json: Submission["json"] | undefined;
518 text: Submission["text"] | undefined;
519 };
520 Submitting: {
521 state: "submitting";
522 location: Location;
523 matches: DataRouteMatch[];
524 historyAction: Action;
525 formMethod: Submission["formMethod"];
526 formAction: Submission["formAction"];
527 formEncType: Submission["formEncType"];
528 formData: Submission["formData"];
529 json: Submission["json"];
530 text: Submission["text"];
531 };
532};
533type Navigation = NavigationStates[keyof NavigationStates];
534type RevalidationState = "idle" | "loading";
535/**
536 * Potential states for fetchers
537 */
538type FetcherStates<TData = any> = {
539 /**
540 * The fetcher is not calling a loader or action
541 *
542 * ```tsx
543 * fetcher.state === "idle"
544 * ```
545 */
546 Idle: {
547 state: "idle";
548 formMethod: undefined;
549 formAction: undefined;
550 formEncType: undefined;
551 text: undefined;
552 formData: undefined;
553 json: undefined;
554 /**
555 * If the fetcher has never been called, this will be undefined.
556 */
557 data: TData | undefined;
558 };
559 /**
560 * The fetcher is loading data from a {@link LoaderFunction | loader} from a
561 * call to {@link FetcherWithComponents.load | `fetcher.load`}.
562 *
563 * ```tsx
564 * // somewhere
565 * <button onClick={() => fetcher.load("/some/route") }>Load</button>
566 *
567 * // the state will update
568 * fetcher.state === "loading"
569 * ```
570 */
571 Loading: {
572 state: "loading";
573 formMethod: Submission["formMethod"] | undefined;
574 formAction: Submission["formAction"] | undefined;
575 formEncType: Submission["formEncType"] | undefined;
576 text: Submission["text"] | undefined;
577 formData: Submission["formData"] | undefined;
578 json: Submission["json"] | undefined;
579 data: TData | undefined;
580 };
581 /**
582 The fetcher is submitting to a {@link LoaderFunction} (GET) or {@link ActionFunction} (POST) from a {@link FetcherWithComponents.Form | `fetcher.Form`} or {@link FetcherWithComponents.submit | `fetcher.submit`}.
583 ```tsx
584 // somewhere
585 <input
586 onChange={e => {
587 fetcher.submit(event.currentTarget.form, { method: "post" });
588 }}
589 />
590 // the state will update
591 fetcher.state === "submitting"
592 // and formData will be available
593 fetcher.formData
594 ```
595 */
596 Submitting: {
597 state: "submitting";
598 formMethod: Submission["formMethod"];
599 formAction: Submission["formAction"];
600 formEncType: Submission["formEncType"];
601 text: Submission["text"];
602 formData: Submission["formData"];
603 json: Submission["json"];
604 data: TData | undefined;
605 };
606};
607type Fetcher<TData = any> = FetcherStates<TData>[keyof FetcherStates<TData>];
608interface BlockerBlocked {
609 state: "blocked";
610 reset: () => void;
611 proceed: () => void;
612 location: Location;
613}
614interface BlockerUnblocked {
615 state: "unblocked";
616 reset: undefined;
617 proceed: undefined;
618 location: undefined;
619}
620interface BlockerProceeding {
621 state: "proceeding";
622 reset: undefined;
623 proceed: undefined;
624 location: Location;
625}
626type Blocker = BlockerUnblocked | BlockerBlocked | BlockerProceeding;
627type BlockerFunction = (args: {
628 currentLocation: Location;
629 nextLocation: Location;
630 historyAction: Action;
631}) => boolean;
632declare const IDLE_NAVIGATION: NavigationStates["Idle"];
633declare const IDLE_FETCHER: FetcherStates["Idle"];
634declare const IDLE_BLOCKER: BlockerUnblocked;
635/**
636 * Create a router and listen to history POP navigations
637 */
638declare function createRouter(init: RouterInit): Router;
639interface CreateStaticHandlerOptions {
640 basename?: string;
641 mapRouteProperties?: MapRoutePropertiesFunction;
642 instrumentations?: Pick<ServerInstrumentation, "route">[];
643 future?: Partial<FutureConfig>;
644}
645/**
646 * Create a static handler to perform server-side data loading
647 *
648 * @example
649 * export async function handleRequest(request: Request) {
650 * let { query, dataRoutes } = createStaticHandler(routes);
651 * let context = await query(request);
652 *
653 * if (context instanceof Response) {
654 * return context;
655 * }
656 *
657 * let router = createStaticRouter(dataRoutes, context);
658 * return new Response(
659 * ReactDOMServer.renderToString(<StaticRouterProvider ... />),
660 * { headers: { "Content-Type": "text/html" } }
661 * );
662 * }
663 *
664 * @public
665 * @category Data Routers
666 * @mode data
667 * @param routes The {@link RouteObject | route objects} to create a static
668 * handler for
669 * @param opts Options
670 * @param opts.basename The base URL for the static handler (default: `/`)
671 * @param opts.future Future flags for the static handler
672 * @returns A static handler that can be used to query data for the provided
673 * routes
674 */
675declare function createStaticHandler(routes: RouteObject[], opts?: CreateStaticHandlerOptions): StaticHandler;
676//#endregion
677export { Blocker, BlockerFunction, Fetcher, FutureConfig, GetScrollPositionFunction, GetScrollRestorationKeyFunction, HydrationState, IDLE_BLOCKER, IDLE_FETCHER, IDLE_NAVIGATION, Navigation, NavigationStates, RelativeRoutingType, RevalidationState, Router, RouterFetchOptions, RouterInit, RouterNavigateOptions, RouterState, RouterSubscriber, StaticHandler, StaticHandlerContext, createRouter, createStaticHandler };
\No newline at end of file