react-router 7.9.6 → 7.10.0-pre.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (68) hide show
  1. package/CHANGELOG.md +75 -10
  2. package/dist/development/{browser-BbBXFHbO.d.ts → browser-BpxEZgZC.d.ts} +1 -1
  3. package/dist/development/{browser-C07r42Tt.d.mts → browser-C5z6FZmz.d.mts} +1 -1
  4. package/dist/development/{chunk-4WY6JWTD.mjs → chunk-GIMUO62I.mjs} +208 -221
  5. package/dist/development/{chunk-AMVS5XVJ.js → chunk-KQLPIZ7E.js} +201 -258
  6. package/dist/development/{chunk-PZWDWJAY.js → chunk-RHWHYDYZ.js} +7 -7
  7. package/dist/development/{chunk-G3INQAYP.mjs → chunk-V5RTLP6E.mjs} +15 -5
  8. package/dist/development/{chunk-O4JVZSOY.js → chunk-XHWAND4X.js} +167 -123
  9. package/dist/development/dom-export.d.mts +29 -10
  10. package/dist/development/dom-export.d.ts +29 -10
  11. package/dist/development/dom-export.js +158 -103
  12. package/dist/development/dom-export.mjs +133 -79
  13. package/dist/{production/index-react-server-client-Da3kmxNd.d.ts → development/index-react-server-client-CCjKYJTH.d.ts} +75 -180
  14. package/dist/development/{index-react-server-client-rcoGPJhU.d.mts → index-react-server-client-CipGfVBI.d.mts} +75 -180
  15. package/dist/development/index-react-server-client.d.mts +2 -2
  16. package/dist/development/index-react-server-client.d.ts +2 -2
  17. package/dist/development/index-react-server-client.js +4 -4
  18. package/dist/development/index-react-server-client.mjs +2 -2
  19. package/dist/development/index-react-server.d.mts +19 -4
  20. package/dist/development/index-react-server.d.ts +19 -4
  21. package/dist/development/index-react-server.js +30 -24
  22. package/dist/development/index-react-server.mjs +30 -24
  23. package/dist/development/index.d.mts +19 -15
  24. package/dist/development/index.d.ts +19 -15
  25. package/dist/development/index.js +92 -82
  26. package/dist/development/index.mjs +3 -3
  27. package/dist/{production/instrumentation-Unc20tLk.d.ts → development/instrumentation-BB0wRuqz.d.ts} +93 -11
  28. package/dist/development/lib/types/internal.d.mts +2 -2
  29. package/dist/development/lib/types/internal.d.ts +2 -2
  30. package/dist/development/lib/types/internal.js +1 -1
  31. package/dist/development/lib/types/internal.mjs +1 -1
  32. package/dist/development/{register-QkB3HGjm.d.mts → register-C1RwVJAt.d.mts} +1 -1
  33. package/dist/development/{register-BpU9rFBJ.d.ts → register-ODDAAYlf.d.ts} +1 -1
  34. package/dist/development/{router-CAvh_Drx.d.mts → router-CwNp5l9u.d.mts} +93 -11
  35. package/dist/production/{browser-BbBXFHbO.d.ts → browser-BpxEZgZC.d.ts} +1 -1
  36. package/dist/production/{browser-C07r42Tt.d.mts → browser-C5z6FZmz.d.mts} +1 -1
  37. package/dist/production/{chunk-QN64DHI4.js → chunk-3MVZKESN.js} +167 -123
  38. package/dist/production/{chunk-FUSXQSWG.mjs → chunk-7F5XUDXM.mjs} +208 -221
  39. package/dist/production/{chunk-EAIF67OW.js → chunk-C7S4I3K5.js} +201 -258
  40. package/dist/production/{chunk-FDUMZGKM.mjs → chunk-ISOIFGFA.mjs} +15 -5
  41. package/dist/production/{chunk-G5A35OQU.js → chunk-YU3WNS3T.js} +7 -7
  42. package/dist/production/dom-export.d.mts +29 -10
  43. package/dist/production/dom-export.d.ts +29 -10
  44. package/dist/production/dom-export.js +158 -103
  45. package/dist/production/dom-export.mjs +133 -79
  46. package/dist/{development/index-react-server-client-Da3kmxNd.d.ts → production/index-react-server-client-CCjKYJTH.d.ts} +75 -180
  47. package/dist/production/{index-react-server-client-rcoGPJhU.d.mts → index-react-server-client-CipGfVBI.d.mts} +75 -180
  48. package/dist/production/index-react-server-client.d.mts +2 -2
  49. package/dist/production/index-react-server-client.d.ts +2 -2
  50. package/dist/production/index-react-server-client.js +4 -4
  51. package/dist/production/index-react-server-client.mjs +2 -2
  52. package/dist/production/index-react-server.d.mts +19 -4
  53. package/dist/production/index-react-server.d.ts +19 -4
  54. package/dist/production/index-react-server.js +30 -24
  55. package/dist/production/index-react-server.mjs +30 -24
  56. package/dist/production/index.d.mts +19 -15
  57. package/dist/production/index.d.ts +19 -15
  58. package/dist/production/index.js +92 -82
  59. package/dist/production/index.mjs +3 -3
  60. package/dist/{development/instrumentation-Unc20tLk.d.ts → production/instrumentation-BB0wRuqz.d.ts} +93 -11
  61. package/dist/production/lib/types/internal.d.mts +2 -2
  62. package/dist/production/lib/types/internal.d.ts +2 -2
  63. package/dist/production/lib/types/internal.js +1 -1
  64. package/dist/production/lib/types/internal.mjs +1 -1
  65. package/dist/production/{register-QkB3HGjm.d.mts → register-C1RwVJAt.d.mts} +1 -1
  66. package/dist/production/{register-BpU9rFBJ.d.ts → register-ODDAAYlf.d.ts} +1 -1
  67. package/dist/production/{router-CAvh_Drx.d.mts → router-CwNp5l9u.d.mts} +93 -11
  68. package/package.json +1 -1
@@ -1,5 +1,5 @@
1
1
  /**
2
- * react-router v7.9.6
2
+ * react-router v7.10.0-pre.1
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
@@ -14,7 +14,7 @@ import {
14
14
  deserializeErrors,
15
15
  getHydrationData,
16
16
  populateRSCRouteModules
17
- } from "./chunk-FDUMZGKM.mjs";
17
+ } from "./chunk-ISOIFGFA.mjs";
18
18
  import {
19
19
  CRITICAL_CSS_DATA_ATTRIBUTE,
20
20
  ErrorResponseImpl,
@@ -22,7 +22,6 @@ import {
22
22
  RSCRouterContext,
23
23
  RemixErrorBoundary,
24
24
  RouterProvider,
25
- UNSTABLE_TransitionEnabledRouterProvider,
26
25
  createBrowserHistory,
27
26
  createClientRoutes,
28
27
  createClientRoutesWithHMRRevalidationOptOut,
@@ -43,7 +42,7 @@ import {
43
42
  singleFetchUrl,
44
43
  stripIndexParam,
45
44
  useFogOFWarDiscovery
46
- } from "./chunk-FUSXQSWG.mjs";
45
+ } from "./chunk-7F5XUDXM.mjs";
47
46
 
48
47
  // lib/dom-export/dom-router-provider.tsx
49
48
  import * as React from "react";
@@ -245,6 +244,7 @@ function HydratedRouter(props) {
245
244
  RouterProvider2,
246
245
  {
247
246
  router,
247
+ unstable_useTransitions: props.unstable_useTransitions,
248
248
  unstable_onError: props.unstable_onError
249
249
  }
250
250
  ))
@@ -283,66 +283,68 @@ function createCallServer({
283
283
  temporaryReferences
284
284
  });
285
285
  });
286
- globalVar.__reactRouterDataRouter.__setPendingRerender(
287
- Promise.resolve(payloadPromise).then(async (payload) => {
288
- if (payload.type === "redirect") {
289
- if (payload.reload || isExternalLocation(payload.location)) {
290
- window.location.href = payload.location;
291
- return () => {
292
- };
293
- }
294
- return () => {
295
- globalVar.__reactRouterDataRouter.navigate(payload.location, {
296
- replace: payload.replace
297
- });
298
- };
299
- }
300
- if (payload.type !== "action") {
301
- throw new Error("Unexpected payload type");
302
- }
303
- const rerender = await payload.rerender;
304
- if (rerender && landedActionId < actionId && globalVar.__routerActionID <= actionId) {
305
- if (rerender.type === "redirect") {
306
- if (rerender.reload || isExternalLocation(rerender.location)) {
307
- window.location.href = rerender.location;
286
+ React3.startTransition(
287
+ () => (
288
+ // @ts-expect-error - Needs React 19 types
289
+ Promise.resolve(payloadPromise).then(async (payload) => {
290
+ if (payload.type === "redirect") {
291
+ if (payload.reload || isExternalLocation(payload.location)) {
292
+ window.location.href = payload.location;
308
293
  return;
309
294
  }
310
- return () => {
311
- globalVar.__reactRouterDataRouter.navigate(rerender.location, {
312
- replace: rerender.replace
295
+ React3.startTransition(() => {
296
+ globalVar.__reactRouterDataRouter.navigate(payload.location, {
297
+ replace: payload.replace
313
298
  });
314
- };
299
+ });
300
+ return;
315
301
  }
316
- return () => {
317
- let lastMatch;
318
- for (const match of rerender.matches) {
319
- globalVar.__reactRouterDataRouter.patchRoutes(
320
- lastMatch?.id ?? null,
321
- [createRouteFromServerManifest(match)],
322
- true
323
- );
324
- lastMatch = match;
302
+ if (payload.type !== "action") {
303
+ throw new Error("Unexpected payload type");
304
+ }
305
+ const rerender = await payload.rerender;
306
+ if (rerender && landedActionId < actionId && globalVar.__routerActionID <= actionId) {
307
+ if (rerender.type === "redirect") {
308
+ if (rerender.reload || isExternalLocation(rerender.location)) {
309
+ window.location.href = rerender.location;
310
+ return;
311
+ }
312
+ React3.startTransition(() => {
313
+ globalVar.__reactRouterDataRouter.navigate(rerender.location, {
314
+ replace: rerender.replace
315
+ });
316
+ });
317
+ return;
325
318
  }
326
- window.__reactRouterDataRouter._internalSetStateDoNotUseOrYouWillBreakYourApp(
327
- {
328
- loaderData: Object.assign(
329
- {},
330
- globalVar.__reactRouterDataRouter.state.loaderData,
331
- rerender.loaderData
332
- ),
333
- errors: rerender.errors ? Object.assign(
334
- {},
335
- globalVar.__reactRouterDataRouter.state.errors,
336
- rerender.errors
337
- ) : null
319
+ React3.startTransition(() => {
320
+ let lastMatch;
321
+ for (const match of rerender.matches) {
322
+ globalVar.__reactRouterDataRouter.patchRoutes(
323
+ lastMatch?.id ?? null,
324
+ [createRouteFromServerManifest(match)],
325
+ true
326
+ );
327
+ lastMatch = match;
338
328
  }
339
- );
340
- };
341
- }
342
- return () => {
343
- };
344
- }).catch(() => {
345
- })
329
+ window.__reactRouterDataRouter._internalSetStateDoNotUseOrYouWillBreakYourApp(
330
+ {
331
+ loaderData: Object.assign(
332
+ {},
333
+ globalVar.__reactRouterDataRouter.state.loaderData,
334
+ rerender.loaderData
335
+ ),
336
+ errors: rerender.errors ? Object.assign(
337
+ {},
338
+ globalVar.__reactRouterDataRouter.state.errors,
339
+ rerender.errors
340
+ ) : null
341
+ }
342
+ );
343
+ });
344
+ }
345
+ }).catch(() => {
346
+ })
347
+ )
346
348
  );
347
349
  return payloadPromise.then((payload) => {
348
350
  if (payload.type !== "action" && payload.type !== "redirect") {
@@ -541,18 +543,20 @@ function getRSCSingleFetchDataStrategy(getRouter, ssr, basename, createFromReada
541
543
  }
542
544
  renderedRoutesById.get(route.id).push(route);
543
545
  }
544
- for (const match of args.matches) {
545
- const renderedRoutes = renderedRoutesById.get(match.route.id);
546
- if (renderedRoutes) {
547
- for (const rendered of renderedRoutes) {
548
- window.__reactRouterDataRouter.patchRoutes(
549
- rendered.parentId ?? null,
550
- [createRouteFromServerManifest(rendered)],
551
- true
552
- );
546
+ React3.startTransition(() => {
547
+ for (const match of args.matches) {
548
+ const renderedRoutes = renderedRoutesById.get(match.route.id);
549
+ if (renderedRoutes) {
550
+ for (const rendered of renderedRoutes) {
551
+ window.__reactRouterDataRouter.patchRoutes(
552
+ rendered.parentId ?? null,
553
+ [createRouteFromServerManifest(rendered)],
554
+ true
555
+ );
556
+ }
553
557
  }
554
558
  }
555
- }
559
+ });
556
560
  return results;
557
561
  });
558
562
  }
@@ -638,14 +642,29 @@ function RSCHydratedRouter({
638
642
  globalVar.__reactRouterDataRouter.initialize();
639
643
  }
640
644
  }, []);
641
- let [location2, setLocation] = React3.useState(router2.state.location);
645
+ let [{ routes, state }, setState] = React3.useState(() => ({
646
+ routes: cloneRoutes(router2.routes),
647
+ state: router2.state
648
+ }));
642
649
  React3.useLayoutEffect(
643
650
  () => router2.subscribe((newState) => {
644
- if (newState.location !== location2) {
645
- setLocation(newState.location);
646
- }
651
+ if (diffRoutes(router2.routes, routes))
652
+ React3.startTransition(() => {
653
+ setState({
654
+ routes: cloneRoutes(router2.routes),
655
+ state: newState
656
+ });
657
+ });
658
+ }),
659
+ [router2.subscribe, routes, router2]
660
+ );
661
+ const transitionEnabledRouter = React3.useMemo(
662
+ () => ({
663
+ ...router2,
664
+ state,
665
+ routes
647
666
  }),
648
- [router2, location2]
667
+ [router2, routes, state]
649
668
  );
650
669
  React3.useEffect(() => {
651
670
  if (routeDiscovery === "lazy" || // @ts-expect-error - TS doesn't know about this yet
@@ -716,7 +735,14 @@ function RSCHydratedRouter({
716
735
  routeDiscovery: { mode: "lazy", manifestPath: "/__manifest" },
717
736
  routeModules
718
737
  };
719
- return /* @__PURE__ */ React3.createElement(RSCRouterContext.Provider, { value: true }, /* @__PURE__ */ React3.createElement(RSCRouterGlobalErrorBoundary, { location: location2 }, /* @__PURE__ */ React3.createElement(FrameworkContext.Provider, { value: frameworkContext }, /* @__PURE__ */ React3.createElement(UNSTABLE_TransitionEnabledRouterProvider, { router: router2, flushSync: ReactDOM2.flushSync }))));
738
+ return /* @__PURE__ */ React3.createElement(RSCRouterContext.Provider, { value: true }, /* @__PURE__ */ React3.createElement(RSCRouterGlobalErrorBoundary, { location: state.location }, /* @__PURE__ */ React3.createElement(FrameworkContext.Provider, { value: frameworkContext }, /* @__PURE__ */ React3.createElement(
739
+ RouterProvider,
740
+ {
741
+ router: transitionEnabledRouter,
742
+ flushSync: ReactDOM2.flushSync,
743
+ unstable_useTransitions: true
744
+ }
745
+ ))));
720
746
  }
721
747
  function createRouteFromServerManifest(match, payload) {
722
748
  let hasInitialData = payload && match.id in payload.loaderData;
@@ -852,11 +878,13 @@ async function fetchAndApplyManifestPatches(paths, createFromReadableStream, fet
852
878
  throw new Error("Failed to patch routes");
853
879
  }
854
880
  paths.forEach((p) => addToFifoQueue(p, discoveredPaths));
855
- payload.patches.forEach((p) => {
856
- window.__reactRouterDataRouter.patchRoutes(
857
- p.parentId ?? null,
858
- [createRouteFromServerManifest(p)]
859
- );
881
+ React3.startTransition(() => {
882
+ payload.patches.forEach((p) => {
883
+ window.__reactRouterDataRouter.patchRoutes(
884
+ p.parentId ?? null,
885
+ [createRouteFromServerManifest(p)]
886
+ );
887
+ });
860
888
  });
861
889
  }
862
890
  function addToFifoQueue(path, queue) {
@@ -877,6 +905,32 @@ function isExternalLocation(location2) {
877
905
  const newLocation = new URL(location2, window.location.href);
878
906
  return newLocation.origin !== window.location.origin;
879
907
  }
908
+ function cloneRoutes(routes) {
909
+ if (!routes) return void 0;
910
+ return routes.map((route) => ({
911
+ ...route,
912
+ children: cloneRoutes(route.children)
913
+ }));
914
+ }
915
+ function diffRoutes(a, b) {
916
+ if (a.length !== b.length) return true;
917
+ return a.some((route, index) => {
918
+ if (route.element !== b[index].element) return true;
919
+ if (route.errorElement !== b[index].errorElement)
920
+ return true;
921
+ if (route.hydrateFallbackElement !== b[index].hydrateFallbackElement)
922
+ return true;
923
+ if (route.hasErrorBoundary !== b[index].hasErrorBoundary)
924
+ return true;
925
+ if (route.hasLoader !== b[index].hasLoader) return true;
926
+ if (route.hasClientLoader !== b[index].hasClientLoader)
927
+ return true;
928
+ if (route.hasAction !== b[index].hasAction) return true;
929
+ if (route.hasClientAction !== b[index].hasClientAction)
930
+ return true;
931
+ return diffRoutes(route.children || [], b[index].children || []);
932
+ });
933
+ }
880
934
 
881
935
  // lib/rsc/html-stream/browser.ts
882
936
  function getRSCStream() {
@@ -1,4 +1,4 @@
1
- import { bE as RouteManifest, o as RouteModules, Q as HydrationState, a1 as DataRouteObject, a as ClientLoaderFunction, a5 as StaticHandlerContext, bF as ServerRouteModule, q as MiddlewareEnabled, c as RouterContextProvider, r as AppLoadContext, al as LoaderFunctionArgs, ac as ActionFunctionArgs, au as unstable_ServerInstrumentation, aj as HTMLFormMethod, ah as FormEncType, w as RelativeRoutingType, bh as PageLinkDescriptor, T as To, bG as History, a4 as GetScrollRestorationKeyFunction, e as RouterInit, bH as FutureConfig$1, u as unstable_ClientInstrumentation, p as DataStrategyFunction, a0 as PatchRoutesOnNavigationFunction, s as NavigateOptions, a6 as Fetcher, K as RouteObject, n as Router, v as SerializeFrom, B as BlockerFunction, L as Location, bI as CreateStaticHandlerOptions$1, a2 as StaticHandler } from './instrumentation-Unc20tLk.js';
1
+ import { bE as RouteManifest, o as RouteModules, Q as HydrationState, a1 as DataRouteObject, a as ClientLoaderFunction, a5 as StaticHandlerContext, bF as ServerRouteModule, q as MiddlewareEnabled, c as RouterContextProvider, r as AppLoadContext, al as LoaderFunctionArgs, ac as ActionFunctionArgs, au as unstable_ServerInstrumentation, aj as HTMLFormMethod, ah as FormEncType, w as RelativeRoutingType, bh as PageLinkDescriptor, T as To, bG as History, a4 as GetScrollRestorationKeyFunction, e as RouterInit, bH as FutureConfig$1, u as unstable_ClientInstrumentation, p as DataStrategyFunction, a0 as PatchRoutesOnNavigationFunction, s as NavigateOptions, a6 as Fetcher, K as RouteObject, n as Router, v as SerializeFrom, B as BlockerFunction, L as Location, bI as CreateStaticHandlerOptions$1, a2 as StaticHandler } from './instrumentation-BB0wRuqz.js';
2
2
  import * as React from 'react';
3
3
 
4
4
  interface Route {
@@ -536,7 +536,7 @@ interface DOMRouterOpts {
536
536
  * added routes via `route.lazy` or `patchRoutesOnNavigation`). This is
537
537
  * mostly useful for observability such as wrapping navigations, fetches,
538
538
  * as well as route loaders/actions/middlewares with logging and/or performance
539
- * tracing.
539
+ * tracing. See the [docs](../../how-to/instrumentation) for more information.
540
540
  *
541
541
  * ```tsx
542
542
  * let router = createBrowserRouter(routes, {
@@ -580,189 +580,32 @@ interface DOMRouterOpts {
580
580
  */
581
581
  unstable_instrumentations?: unstable_ClientInstrumentation[];
582
582
  /**
583
- * Override the default data strategy of running loaders in parallel.
584
- * See {@link DataStrategyFunction}.
585
- *
586
- * <docs-warning>This is a low-level API intended for advanced use-cases. This
587
- * overrides React Router's internal handling of
588
- * [`action`](../../start/data/route-object#action)/[`loader`](../../start/data/route-object#loader)
589
- * execution, and if done incorrectly will break your app code. Please use
590
- * with caution and perform the appropriate testing.</docs-warning>
591
- *
592
- * By default, React Router is opinionated about how your data is loaded/submitted -
593
- * and most notably, executes all of your [`loader`](../../start/data/route-object#loader)s
594
- * in parallel for optimal data fetching. While we think this is the right
595
- * behavior for most use-cases, we realize that there is no "one size fits all"
596
- * solution when it comes to data fetching for the wide landscape of
597
- * application requirements.
598
- *
599
- * The `dataStrategy` option gives you full control over how your [`action`](../../start/data/route-object#action)s
600
- * and [`loader`](../../start/data/route-object#loader)s are executed and lays
601
- * the foundation to build in more advanced APIs such as middleware, context,
602
- * and caching layers. Over time, we expect that we'll leverage this API
603
- * internally to bring more first class APIs to React Router, but until then
604
- * (and beyond), this is your way to add more advanced functionality for your
605
- * application's data needs.
606
- *
607
- * The `dataStrategy` function should return a key/value-object of
608
- * `routeId` -> {@link DataStrategyResult} and should include entries for any
609
- * routes where a handler was executed. A `DataStrategyResult` indicates if
610
- * the handler was successful or not based on the `DataStrategyResult.type`
611
- * field. If the returned `DataStrategyResult.result` is a [`Response`](https://developer.mozilla.org/en-US/docs/Web/API/Response),
612
- * React Router will unwrap it for you (via [`res.json`](https://developer.mozilla.org/en-US/docs/Web/API/Response/json)
613
- * or [`res.text`](https://developer.mozilla.org/en-US/docs/Web/API/Response/text)).
614
- * If you need to do custom decoding of a [`Response`](https://developer.mozilla.org/en-US/docs/Web/API/Response)
615
- * but want to preserve the status code, you can use the `data` utility to
616
- * return your decoded data along with a `ResponseInit`.
617
- *
618
- * <details>
619
- * <summary><b>Example <code>dataStrategy</code> Use Cases</b></summary>
620
- *
621
- * **Adding logging**
622
- *
623
- * In the simplest case, let's look at hooking into this API to add some logging
624
- * for when our route [`action`](../../start/data/route-object#action)s/[`loader`](../../start/data/route-object#loader)s
625
- * execute:
583
+ * Override the default data strategy of running loaders in parallel -
584
+ * see the [docs](../../how-to/data-strategy) for more information.
626
585
  *
627
586
  * ```tsx
628
587
  * let router = createBrowserRouter(routes, {
629
- * async dataStrategy({ matches, request }) {
630
- * const matchesToLoad = matches.filter((m) => m.shouldLoad);
631
- * const results: Record<string, DataStrategyResult> = {};
632
- * await Promise.all(
633
- * matchesToLoad.map(async (match) => {
634
- * console.log(`Processing ${match.route.id}`);
635
- * results[match.route.id] = await match.resolve();;
636
- * })
588
+ * async dataStrategy({
589
+ * matches,
590
+ * request,
591
+ * runClientMiddleware,
592
+ * }) {
593
+ * const matchesToLoad = matches.filter((m) =>
594
+ * m.shouldCallHandler(),
637
595
  * );
638
- * return results;
639
- * },
640
- * });
641
- * ```
642
- *
643
- * **Middleware**
644
- *
645
- * Let's define a middleware on each route via [`handle`](../../start/data/route-object#handle)
646
- * and call middleware sequentially first, then call all
647
- * [`loader`](../../start/data/route-object#loader)s in parallel - providing
648
- * any data made available via the middleware:
649
- *
650
- * ```ts
651
- * const routes = [
652
- * {
653
- * id: "parent",
654
- * path: "/parent",
655
- * loader({ request }, context) {
656
- * // ...
657
- * },
658
- * handle: {
659
- * async middleware({ request }, context) {
660
- * context.parent = "PARENT MIDDLEWARE";
661
- * },
662
- * },
663
- * children: [
664
- * {
665
- * id: "child",
666
- * path: "child",
667
- * loader({ request }, context) {
668
- * // ...
669
- * },
670
- * handle: {
671
- * async middleware({ request }, context) {
672
- * context.child = "CHILD MIDDLEWARE";
673
- * },
674
- * },
675
- * },
676
- * ],
677
- * },
678
- * ];
679
596
  *
680
- * let router = createBrowserRouter(routes, {
681
- * async dataStrategy({ matches, params, request }) {
682
- * // Run middleware sequentially and let them add data to `context`
683
- * let context = {};
684
- * for (const match of matches) {
685
- * if (match.route.handle?.middleware) {
686
- * await match.route.handle.middleware(
687
- * { request, params },
688
- * context
689
- * );
690
- * }
691
- * }
692
- *
693
- * // Run loaders in parallel with the `context` value
694
- * let matchesToLoad = matches.filter((m) => m.shouldLoad);
695
- * let results = await Promise.all(
696
- * matchesToLoad.map((match, i) =>
697
- * match.resolve((handler) => {
698
- * // Whatever you pass to `handler` will be passed as the 2nd parameter
699
- * // to your loader/action
700
- * return handler(context);
701
- * })
702
- * )
703
- * );
704
- * return results.reduce(
705
- * (acc, result, i) =>
706
- * Object.assign(acc, {
707
- * [matchesToLoad[i].route.id]: result,
597
+ * const results: Record<string, DataStrategyResult> = {};
598
+ * await runClientMiddleware(() =>
599
+ * Promise.all(
600
+ * matchesToLoad.map(async (match) => {
601
+ * results[match.route.id] = await match.resolve();
708
602
  * }),
709
- * {}
603
+ * ),
710
604
  * );
711
- * },
712
- * });
713
- * ```
714
- *
715
- * **Custom Handler**
716
- *
717
- * It's also possible you don't even want to define a [`loader`](../../start/data/route-object#loader)
718
- * implementation at the route level. Maybe you want to just determine the
719
- * routes and issue a single GraphQL request for all of your data? You can do
720
- * that by setting your `route.loader=true` so it qualifies as "having a
721
- * loader", and then store GQL fragments on `route.handle`:
722
- *
723
- * ```ts
724
- * const routes = [
725
- * {
726
- * id: "parent",
727
- * path: "/parent",
728
- * loader: true,
729
- * handle: {
730
- * gql: gql`
731
- * fragment Parent on Whatever {
732
- * parentField
733
- * }
734
- * `,
735
- * },
736
- * children: [
737
- * {
738
- * id: "child",
739
- * path: "child",
740
- * loader: true,
741
- * handle: {
742
- * gql: gql`
743
- * fragment Child on Whatever {
744
- * childField
745
- * }
746
- * `,
747
- * },
748
- * },
749
- * ],
750
- * },
751
- * ];
752
- *
753
- * let router = createBrowserRouter(routes, {
754
- * async dataStrategy({ matches, params, request }) {
755
- * // Compose route fragments into a single GQL payload
756
- * let gql = getFragmentsFromRouteHandles(matches);
757
- * let data = await fetchGql(gql);
758
- * // Parse results back out into individual route level `DataStrategyResult`'s
759
- * // keyed by `routeId`
760
- * let results = parseResultsFromGql(data);
761
605
  * return results;
762
606
  * },
763
607
  * });
764
608
  * ```
765
- *</details>
766
609
  */
767
610
  dataStrategy?: DataStrategyFunction;
768
611
  /**
@@ -1122,6 +965,21 @@ interface BrowserRouterProps {
1122
965
  * {@link Route | `<Route>`} components describing your route configuration
1123
966
  */
1124
967
  children?: React.ReactNode;
968
+ /**
969
+ * Control whether router state updates are internally wrapped in
970
+ * [`React.startTransition`](https://react.dev/reference/react/startTransition).
971
+ *
972
+ * - When left `undefined`, all router state updates are wrapped in
973
+ * `React.startTransition`
974
+ * - When set to `true`, {@link Link} and {@link Form} navigations will be wrapped
975
+ * in `React.startTransition` and all router state updates are wrapped in
976
+ * `React.startTransition`
977
+ * - When set to `false`, the router will not leverage `React.startTransition`
978
+ * on any navigations or state changes.
979
+ *
980
+ * For more information, please see the [docs](https://reactrouter.com/explanation/react-transitions).
981
+ */
982
+ unstable_useTransitions?: boolean;
1125
983
  /**
1126
984
  * [`Window`](https://developer.mozilla.org/en-US/docs/Web/API/Window) object
1127
985
  * override. Defaults to the global `window` instance
@@ -1138,11 +996,12 @@ interface BrowserRouterProps {
1138
996
  * @param props Props
1139
997
  * @param {BrowserRouterProps.basename} props.basename n/a
1140
998
  * @param {BrowserRouterProps.children} props.children n/a
999
+ * @param {BrowserRouterProps.unstable_useTransitions} props.unstable_useTransitions n/a
1141
1000
  * @param {BrowserRouterProps.window} props.window n/a
1142
1001
  * @returns A declarative {@link Router | `<Router>`} using the browser [`History`](https://developer.mozilla.org/en-US/docs/Web/API/History)
1143
1002
  * API for client-side routing.
1144
1003
  */
1145
- declare function BrowserRouter({ basename, children, window, }: BrowserRouterProps): React.JSX.Element;
1004
+ declare function BrowserRouter({ basename, children, unstable_useTransitions, window, }: BrowserRouterProps): React.JSX.Element;
1146
1005
  /**
1147
1006
  * @category Types
1148
1007
  */
@@ -1155,6 +1014,21 @@ interface HashRouterProps {
1155
1014
  * {@link Route | `<Route>`} components describing your route configuration
1156
1015
  */
1157
1016
  children?: React.ReactNode;
1017
+ /**
1018
+ * Control whether router state updates are internally wrapped in
1019
+ * [`React.startTransition`](https://react.dev/reference/react/startTransition).
1020
+ *
1021
+ * - When left `undefined`, all router state updates are wrapped in
1022
+ * `React.startTransition`
1023
+ * - When set to `true`, {@link Link} and {@link Form} navigations will be wrapped
1024
+ * in `React.startTransition` and all router state updates are wrapped in
1025
+ * `React.startTransition`
1026
+ * - When set to `false`, the router will not leverage `React.startTransition`
1027
+ * on any navigations or state changes.
1028
+ *
1029
+ * For more information, please see the [docs](https://reactrouter.com/explanation/react-transitions).
1030
+ */
1031
+ unstable_useTransitions?: boolean;
1158
1032
  /**
1159
1033
  * [`Window`](https://developer.mozilla.org/en-US/docs/Web/API/Window) object
1160
1034
  * override. Defaults to the global `window` instance
@@ -1172,11 +1046,12 @@ interface HashRouterProps {
1172
1046
  * @param props Props
1173
1047
  * @param {HashRouterProps.basename} props.basename n/a
1174
1048
  * @param {HashRouterProps.children} props.children n/a
1049
+ * @param {HashRouterProps.unstable_useTransitions} props.unstable_useTransitions n/a
1175
1050
  * @param {HashRouterProps.window} props.window n/a
1176
1051
  * @returns A declarative {@link Router | `<Router>`} using the URL [`hash`](https://developer.mozilla.org/en-US/docs/Web/API/URL/hash)
1177
1052
  * for client-side routing.
1178
1053
  */
1179
- declare function HashRouter({ basename, children, window }: HashRouterProps): React.JSX.Element;
1054
+ declare function HashRouter({ basename, children, unstable_useTransitions, window, }: HashRouterProps): React.JSX.Element;
1180
1055
  /**
1181
1056
  * @category Types
1182
1057
  */
@@ -1193,6 +1068,21 @@ interface HistoryRouterProps {
1193
1068
  * A {@link History} implementation for use by the router
1194
1069
  */
1195
1070
  history: History;
1071
+ /**
1072
+ * Control whether router state updates are internally wrapped in
1073
+ * [`React.startTransition`](https://react.dev/reference/react/startTransition).
1074
+ *
1075
+ * - When left `undefined`, all router state updates are wrapped in
1076
+ * `React.startTransition`
1077
+ * - When set to `true`, {@link Link} and {@link Form} navigations will be wrapped
1078
+ * in `React.startTransition` and all router state updates are wrapped in
1079
+ * `React.startTransition`
1080
+ * - When set to `false`, the router will not leverage `React.startTransition`
1081
+ * on any navigations or state changes.
1082
+ *
1083
+ * For more information, please see the [docs](https://reactrouter.com/explanation/react-transitions).
1084
+ */
1085
+ unstable_useTransitions?: boolean;
1196
1086
  }
1197
1087
  /**
1198
1088
  * A declarative {@link Router | `<Router>`} that accepts a pre-instantiated
@@ -1209,10 +1099,11 @@ interface HistoryRouterProps {
1209
1099
  * @param {HistoryRouterProps.basename} props.basename n/a
1210
1100
  * @param {HistoryRouterProps.children} props.children n/a
1211
1101
  * @param {HistoryRouterProps.history} props.history n/a
1102
+ * @param {HistoryRouterProps.unstable_useTransitions} props.unstable_useTransitions n/a
1212
1103
  * @returns A declarative {@link Router | `<Router>`} using the provided history
1213
1104
  * implementation for client-side routing.
1214
1105
  */
1215
- declare function HistoryRouter({ basename, children, history, }: HistoryRouterProps): React.JSX.Element;
1106
+ declare function HistoryRouter({ basename, children, history, unstable_useTransitions, }: HistoryRouterProps): React.JSX.Element;
1216
1107
  declare namespace HistoryRouter {
1217
1108
  var displayName: string;
1218
1109
  }
@@ -1830,15 +1721,19 @@ declare namespace ScrollRestoration {
1830
1721
  * @param options.viewTransition Enables a [View Transition](https://developer.mozilla.org/en-US/docs/Web/API/View_Transitions_API)
1831
1722
  * for this navigation. To apply specific styles during the transition, see
1832
1723
  * {@link useViewTransitionState}. Defaults to `false`.
1724
+ * @param options.unstable_useTransitions Wraps the navigation in
1725
+ * [`React.startTransition`](https://react.dev/reference/react/startTransition)
1726
+ * for concurrent rendering. Defaults to `false`.
1833
1727
  * @returns A click handler function that can be used in a custom {@link Link} component.
1834
1728
  */
1835
- declare function useLinkClickHandler<E extends Element = HTMLAnchorElement>(to: To, { target, replace: replaceProp, state, preventScrollReset, relative, viewTransition, }?: {
1729
+ declare function useLinkClickHandler<E extends Element = HTMLAnchorElement>(to: To, { target, replace: replaceProp, state, preventScrollReset, relative, viewTransition, unstable_useTransitions, }?: {
1836
1730
  target?: React.HTMLAttributeAnchorTarget;
1837
1731
  replace?: boolean;
1838
1732
  state?: any;
1839
1733
  preventScrollReset?: boolean;
1840
1734
  relative?: RelativeRoutingType;
1841
1735
  viewTransition?: boolean;
1736
+ unstable_useTransitions?: boolean;
1842
1737
  }): (event: React.MouseEvent<E, MouseEvent>) => void;
1843
1738
  /**
1844
1739
  * Returns a tuple of the current URL's [`URLSearchParams`](https://developer.mozilla.org/en-US/docs/Web/API/URLSearchParams)
@@ -2167,7 +2062,7 @@ type FetcherWithComponents<TData> = Fetcher<TData> & {
2167
2062
  * @param reason Optional `reason` to provide to [`AbortController.abort()`](https://developer.mozilla.org/en-US/docs/Web/API/AbortController/abort)
2168
2063
  * @returns void
2169
2064
  */
2170
- unstable_reset: (opts?: {
2065
+ reset: (opts?: {
2171
2066
  reason?: unknown;
2172
2067
  }) => void;
2173
2068
  /**
@@ -2256,7 +2151,7 @@ type FetcherWithComponents<TData> = Fetcher<TData> & {
2256
2151
  * })
2257
2152
  *
2258
2153
  * // reset fetcher
2259
- * fetcher.unstable_reset()
2154
+ * fetcher.reset()
2260
2155
  * }
2261
2156
  *
2262
2157
  * @public