INDIE UNPKG

20.9 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 /** @internal Enables application-controlled Framework route discovery. */
310 unstable_customRouteDiscovery?: boolean;
311 /** Enables route-pattern matching after calling `unstable_preloadRoutePattern()`. */
312 unstable_routePatternMatching?: boolean;
313}
314/**
315 * Initialization options for createRouter
316 */
317interface RouterInit {
318 routes: RouteObject[];
319 history: History;
320 basename?: string;
321 getContext?: () => MaybePromise<RouterContextProvider>;
322 instrumentations?: ClientInstrumentation[];
323 mapRouteProperties?: MapRoutePropertiesFunction;
324 future?: Partial<FutureConfig>;
325 hydrationRouteProperties?: string[];
326 hydrationData?: HydrationState;
327 window?: Window;
328 dataStrategy?: DataStrategyFunction;
329 patchRoutesOnNavigation?: PatchRoutesOnNavigationFunction;
330}
331/**
332 * State returned from a server-side query() call
333 */
334interface StaticHandlerContext {
335 basename: Router["basename"];
336 location: RouterState["location"];
337 matches: RouterState["matches"];
338 loaderData: RouterState["loaderData"];
339 actionData: RouterState["actionData"];
340 errors: RouterState["errors"];
341 statusCode: number;
342 loaderHeaders: Record<string, Headers>;
343 actionHeaders: Record<string, Headers>;
344 _deepestRenderedBoundaryId?: string | null;
345 /** @private */
346 _match: StaticHandler["match"];
347}
348/**
349 * A StaticHandler instance manages a singular SSR navigation/fetch event
350 */
351interface StaticHandler {
352 /**
353 * The set of data routes managed by this handler
354 */
355 dataRoutes: DataRouteObject[];
356 /**
357 * @private
358 * PRIVATE - DO NOT USE
359 *
360 * Match routes against a location using the handler's configured route
361 * matching implementation.
362 */
363 match(locationArg: Partial<Location> | string): DataRouteMatch[] | null;
364 /**
365 * Perform a query for a given request - executing all matched route
366 * loaders/actions. Used for document requests.
367 *
368 * @param request The request to query
369 * @param opts Optional query options
370 * @param opts.dataStrategy Alternate dataStrategy implementation
371 * @param opts.filterMatchesToLoad Predicate function to filter which matches should be loaded
372 * @param opts.generateMiddlewareResponse To enable middleware, provide a function
373 * to generate a response to bubble back up the middleware chain
374 * @param opts.requestContext Context object to pass to loaders/actions
375 * @param opts.skipLoaderErrorBubbling Skip loader error bubbling
376 * @param opts.skipRevalidation Skip revalidation after action submission
377 * @param opts.normalizePath Normalize the request path
378 */
379 query(request: Request, opts?: {
380 requestContext?: unknown;
381 filterMatchesToLoad?: (match: DataRouteMatch) => boolean;
382 skipLoaderErrorBubbling?: boolean;
383 skipRevalidation?: boolean;
384 dataStrategy?: DataStrategyFunction<unknown>;
385 generateMiddlewareResponse?: (query: (r: Request, args?: {
386 filterMatchesToLoad?: (match: DataRouteMatch) => boolean;
387 }) => Promise<StaticHandlerContext | Response>) => MaybePromise<Response>;
388 normalizePath?: (request: Request) => Path;
389 }): Promise<StaticHandlerContext | Response>;
390 /**
391 * Perform a query for a specific route. Used for resource requests.
392 *
393 * @param request The request to query
394 * @param opts Optional queryRoute options
395 * @param opts.dataStrategy Alternate dataStrategy implementation
396 * @param opts.generateMiddlewareResponse To enable middleware, provide a function
397 * to generate a response to bubble back up the middleware chain
398 * @param opts.requestContext Context object to pass to loaders/actions
399 * @param opts.routeId The ID of the route to query
400 * @param opts.normalizePath Normalize the request path
401 */
402 queryRoute(request: Request, opts?: {
403 routeId?: string;
404 requestContext?: unknown;
405 dataStrategy?: DataStrategyFunction<unknown>;
406 generateMiddlewareResponse?: (queryRoute: (r: Request) => Promise<Response>) => MaybePromise<Response>;
407 normalizePath?: (request: Request) => Path;
408 }): Promise<any>;
409}
410type ViewTransitionOpts = {
411 currentLocation: Location;
412 nextLocation: Location;
413};
414/**
415 * Subscriber function signature for changes to router state
416 */
417interface RouterSubscriber {
418 (state: RouterState, opts: {
419 deletedFetchers: string[];
420 newErrors: RouteData | null;
421 viewTransitionOpts?: ViewTransitionOpts;
422 flushSync: boolean;
423 }): void;
424}
425/**
426 * Function signature for determining the key to be used in scroll restoration
427 * for a given location
428 */
429interface GetScrollRestorationKeyFunction {
430 (location: Location, matches: UIMatch[]): string | null;
431}
432/**
433 * Function signature for determining the current scroll position
434 */
435interface GetScrollPositionFunction {
436 (): number;
437}
438/**
439 * - "route": relative to the route hierarchy so `..` means remove all segments
440 * of the current route even if it has many. For example, a `route("posts/:id")`
441 * would have both `:id` and `posts` removed from the url.
442 * - "path": relative to the pathname so `..` means remove one segment of the
443 * pathname. For example, a `route("posts/:id")` would have only `:id` removed
444 * from the url.
445 */
446type RelativeRoutingType = "route" | "path";
447type BaseNavigateOrFetchOptions = {
448 preventScrollReset?: boolean;
449 relative?: RelativeRoutingType;
450 flushSync?: boolean;
451 defaultShouldRevalidate?: boolean;
452};
453type BaseNavigateOptions = BaseNavigateOrFetchOptions & {
454 replace?: boolean;
455 state?: any;
456 fromRouteId?: string;
457 /**
458 * @deprecated Use React's `<ViewTransition>` component instead. See the
459 * [migration guide](https://reactrouter.com/how-to/view-transitions).
460 */
461 viewTransition?: boolean;
462 mask?: To;
463};
464type BaseSubmissionOptions = {
465 formMethod?: HTMLFormMethod;
466 formEncType?: FormEncType;
467} & ({
468 formData: FormData;
469 body?: undefined;
470} | {
471 formData?: undefined;
472 body: any;
473});
474/**
475 * Options for a navigate() call for a normal (non-submission) navigation
476 */
477type LinkNavigateOptions = BaseNavigateOptions;
478/**
479 * Options for a navigate() call for a submission navigation
480 */
481type SubmissionNavigateOptions = BaseNavigateOptions & BaseSubmissionOptions;
482/**
483 * Options to pass to navigate() for a navigation
484 */
485type RouterNavigateOptions = LinkNavigateOptions | SubmissionNavigateOptions;
486/**
487 * Options for a fetch() load
488 */
489type LoadFetchOptions = BaseNavigateOrFetchOptions;
490/**
491 * Options for a fetch() submission
492 */
493type SubmitFetchOptions = BaseNavigateOrFetchOptions & BaseSubmissionOptions;
494/**
495 * Options to pass to fetch()
496 */
497type RouterFetchOptions = LoadFetchOptions | SubmitFetchOptions;
498/**
499 * Potential states for state.navigation
500 */
501type NavigationStates = {
502 Idle: {
503 state: "idle";
504 location: undefined;
505 matches: undefined;
506 historyAction: undefined;
507 formMethod: undefined;
508 formAction: undefined;
509 formEncType: undefined;
510 formData: undefined;
511 json: undefined;
512 text: undefined;
513 };
514 Loading: {
515 state: "loading";
516 location: Location;
517 matches: DataRouteMatch[];
518 historyAction: Action;
519 formMethod: Submission["formMethod"] | undefined;
520 formAction: Submission["formAction"] | undefined;
521 formEncType: Submission["formEncType"] | undefined;
522 formData: Submission["formData"] | undefined;
523 json: Submission["json"] | undefined;
524 text: Submission["text"] | undefined;
525 };
526 Submitting: {
527 state: "submitting";
528 location: Location;
529 matches: DataRouteMatch[];
530 historyAction: Action;
531 formMethod: Submission["formMethod"];
532 formAction: Submission["formAction"];
533 formEncType: Submission["formEncType"];
534 formData: Submission["formData"];
535 json: Submission["json"];
536 text: Submission["text"];
537 };
538};
539type Navigation = NavigationStates[keyof NavigationStates];
540type RevalidationState = "idle" | "loading";
541/**
542 * Potential states for fetchers
543 */
544type FetcherStates<TData = any> = {
545 /**
546 * The fetcher is not calling a loader or action
547 *
548 * ```tsx
549 * fetcher.state === "idle"
550 * ```
551 */
552 Idle: {
553 state: "idle";
554 formMethod: undefined;
555 formAction: undefined;
556 formEncType: undefined;
557 text: undefined;
558 formData: undefined;
559 json: undefined;
560 /**
561 * If the fetcher has never been called, this will be undefined.
562 */
563 data: TData | undefined;
564 };
565 /**
566 * The fetcher is loading data from a {@link LoaderFunction | loader} from a
567 * call to {@link FetcherWithComponents.load | `fetcher.load`}.
568 *
569 * ```tsx
570 * // somewhere
571 * <button onClick={() => fetcher.load("/some/route") }>Load</button>
572 *
573 * // the state will update
574 * fetcher.state === "loading"
575 * ```
576 */
577 Loading: {
578 state: "loading";
579 formMethod: Submission["formMethod"] | undefined;
580 formAction: Submission["formAction"] | undefined;
581 formEncType: Submission["formEncType"] | undefined;
582 text: Submission["text"] | undefined;
583 formData: Submission["formData"] | undefined;
584 json: Submission["json"] | undefined;
585 data: TData | undefined;
586 };
587 /**
588 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`}.
589 ```tsx
590 // somewhere
591 <input
592 onChange={e => {
593 fetcher.submit(event.currentTarget.form, { method: "post" });
594 }}
595 />
596 // the state will update
597 fetcher.state === "submitting"
598 // and formData will be available
599 fetcher.formData
600 ```
601 */
602 Submitting: {
603 state: "submitting";
604 formMethod: Submission["formMethod"];
605 formAction: Submission["formAction"];
606 formEncType: Submission["formEncType"];
607 text: Submission["text"];
608 formData: Submission["formData"];
609 json: Submission["json"];
610 data: TData | undefined;
611 };
612};
613type Fetcher<TData = any> = FetcherStates<TData>[keyof FetcherStates<TData>];
614interface BlockerBlocked {
615 state: "blocked";
616 reset: () => void;
617 proceed: () => void;
618 location: Location;
619}
620interface BlockerUnblocked {
621 state: "unblocked";
622 reset: undefined;
623 proceed: undefined;
624 location: undefined;
625}
626interface BlockerProceeding {
627 state: "proceeding";
628 reset: undefined;
629 proceed: undefined;
630 location: Location;
631}
632type Blocker = BlockerUnblocked | BlockerBlocked | BlockerProceeding;
633type BlockerFunction = (args: {
634 currentLocation: Location;
635 nextLocation: Location;
636 historyAction: Action;
637}) => boolean;
638declare const IDLE_NAVIGATION: NavigationStates["Idle"];
639declare const IDLE_FETCHER: FetcherStates["Idle"];
640declare const IDLE_BLOCKER: BlockerUnblocked;
641/**
642 * Create a router and listen to history POP navigations
643 */
644declare function createRouter(init: RouterInit): Router;
645interface CreateStaticHandlerOptions {
646 basename?: string;
647 mapRouteProperties?: MapRoutePropertiesFunction;
648 instrumentations?: Pick<ServerInstrumentation, "route">[];
649 future?: Partial<FutureConfig>;
650}
651/**
652 * Create a static handler to perform server-side data loading
653 *
654 * @example
655 * export async function handleRequest(request: Request) {
656 * let { query, dataRoutes } = createStaticHandler(routes);
657 * let context = await query(request);
658 *
659 * if (context instanceof Response) {
660 * return context;
661 * }
662 *
663 * let router = createStaticRouter(dataRoutes, context);
664 * return new Response(
665 * ReactDOMServer.renderToString(<StaticRouterProvider ... />),
666 * { headers: { "Content-Type": "text/html" } }
667 * );
668 * }
669 *
670 * @public
671 * @category Data Routers
672 * @mode data
673 * @param routes The {@link RouteObject | route objects} to create a static
674 * handler for
675 * @param opts Options
676 * @param opts.basename The base URL for the static handler (default: `/`)
677 * @param opts.future Future flags for the static handler
678 * @returns A static handler that can be used to query data for the provided
679 * routes
680 */
681declare function createStaticHandler(routes: RouteObject[], opts?: CreateStaticHandlerOptions): StaticHandler;
682//#endregion
683export { 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