react-router 0.0.0-experimental-7f486334 → 0.0.0-experimental-b24023f3

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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,22 @@
1
1
  # `react-router`
2
2
 
3
+ ## 6.19.0
4
+
5
+ ### Minor Changes
6
+
7
+ - Add `unstable_flushSync` option to `useNavigate`/`useSumbit`/`fetcher.load`/`fetcher.submit` to opt-out of `React.startTransition` and into `ReactDOM.flushSync` for state updates ([#11005](https://github.com/remix-run/react-router/pull/11005))
8
+ - Remove the `unstable_` prefix from the [`useBlocker`](https://reactrouter.com/en/main/hooks/use-blocker) hook as it's been in use for enough time that we are confident in the API. We do not plan to remove the prefix from `unstable_usePrompt` due to differences in how browsers handle `window.confirm` that prevent React Router from guaranteeing consistent/correct behavior. ([#10991](https://github.com/remix-run/react-router/pull/10991))
9
+
10
+ ### Patch Changes
11
+
12
+ - Fix `useActionData` so it returns proper contextual action data and not _any_ action data in the tree ([#11023](https://github.com/remix-run/react-router/pull/11023))
13
+ - Fix bug in `useResolvedPath` that would cause `useResolvedPath(".")` in a splat route to lose the splat portion of the URL path. ([#10983](https://github.com/remix-run/react-router/pull/10983))
14
+
15
+ - ⚠️ This fixes a quite long-standing bug specifically for `"."` paths inside a splat route which incorrectly dropped the splat portion of the URL. If you are relative routing via `"."` inside a splat route in your application you should double check that your logic is not relying on this buggy behavior and update accordingly.
16
+
17
+ - Updated dependencies:
18
+ - `@remix-run/router@1.12.0`
19
+
3
20
  ## 6.18.0
4
21
 
5
22
  ### Patch Changes
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import type { ActionFunction, ActionFunctionArgs, Blocker, BlockerFunction, ErrorResponse, Fetcher, HydrationState, InitialEntry, JsonFunction, LazyRouteFunction, LoaderFunction, LoaderFunctionArgs, Location, Navigation, ParamParseKey, Params, Path, PathMatch, PathPattern, RedirectFunction, RelativeRoutingType, Router as RemixRouter, FutureConfig as RouterFutureConfig, ShouldRevalidateFunction, ShouldRevalidateFunctionArgs, To, UIMatch } from "@remix-run/router";
1
+ import type { ActionFunction, ActionFunctionArgs, Blocker, BlockerFunction, ErrorResponse, Fetcher, HydrationState, InitialEntry, JsonFunction, LazyRouteFunction, LoaderFunction, LoaderFunctionArgs, Location, Navigation, ParamParseKey, Params, Path, PathMatch, PathParam, PathPattern, RedirectFunction, RelativeRoutingType, Router as RemixRouter, FutureConfig as RouterFutureConfig, ShouldRevalidateFunction, ShouldRevalidateFunctionArgs, To, UIMatch } from "@remix-run/router";
2
2
  import { AbortedDeferredError, Action as NavigationType, createPath, defer, generatePath, isRouteErrorResponse, json, matchPath, matchRoutes, parsePath, redirect, redirectDocument, resolvePath } from "@remix-run/router";
3
3
  import type { AwaitProps, FutureConfig, IndexRouteProps, LayoutRouteProps, MemoryRouterProps, NavigateProps, OutletProps, PathRouteProps, RouteProps, RouterProps, RouterProviderProps, RoutesProps } from "./lib/components";
4
4
  import { Await, MemoryRouter, Navigate, Outlet, Route, Router, RouterProvider, Routes, createRoutesFromChildren, renderMatches } from "./lib/components";
@@ -9,7 +9,7 @@ import { useActionData, useAsyncError, useAsyncValue, useBlocker, useHref, useIn
9
9
  type Hash = string;
10
10
  type Pathname = string;
11
11
  type Search = string;
12
- export type { ActionFunction, ActionFunctionArgs, AwaitProps, DataRouteMatch, DataRouteObject, ErrorResponse, Fetcher, FutureConfig, Hash, IndexRouteObject, IndexRouteProps, JsonFunction, LayoutRouteProps, LazyRouteFunction, LoaderFunction, LoaderFunctionArgs, Location, MemoryRouterProps, NavigateFunction, NavigateOptions, NavigateProps, Navigation, Navigator, NonIndexRouteObject, OutletProps, ParamParseKey, Params, Path, PathMatch, PathPattern, PathRouteProps, Pathname, RedirectFunction, RelativeRoutingType, RouteMatch, RouteObject, RouteProps, RouterProps, RouterProviderProps, RoutesProps, Search, ShouldRevalidateFunction, ShouldRevalidateFunctionArgs, To, UIMatch, Blocker as unstable_Blocker, BlockerFunction as unstable_BlockerFunction, };
12
+ export type { ActionFunction, ActionFunctionArgs, AwaitProps, DataRouteMatch, DataRouteObject, ErrorResponse, Fetcher, FutureConfig, Hash, IndexRouteObject, IndexRouteProps, JsonFunction, LayoutRouteProps, LazyRouteFunction, LoaderFunction, LoaderFunctionArgs, Location, MemoryRouterProps, NavigateFunction, NavigateOptions, NavigateProps, Navigation, Navigator, NonIndexRouteObject, OutletProps, ParamParseKey, Params, Path, PathMatch, PathParam, PathPattern, PathRouteProps, Pathname, RedirectFunction, RelativeRoutingType, RouteMatch, RouteObject, RouteProps, RouterProps, RouterProviderProps, RoutesProps, Search, ShouldRevalidateFunction, ShouldRevalidateFunctionArgs, To, UIMatch, Blocker as unstable_Blocker, BlockerFunction as unstable_BlockerFunction, };
13
13
  export { AbortedDeferredError, Await, MemoryRouter, Navigate, NavigationType, Outlet, Route, Router, RouterProvider, Routes, createPath, createRoutesFromChildren, createRoutesFromChildren as createRoutesFromElements, defer, generatePath, isRouteErrorResponse, json, matchPath, matchRoutes, parsePath, redirect, redirectDocument, renderMatches, resolvePath, useBlocker, useActionData, useAsyncError, useAsyncValue, useHref, useInRouterContext, useLoaderData, useLocation, useMatch, useMatches, useNavigate, useNavigation, useNavigationType, useOutlet, useOutletContext, useParams, useResolvedPath, useRevalidator, useRouteError, useRouteLoaderData, useRoutes, };
14
14
  declare function mapRouteProperties(route: RouteObject): Partial<RouteObject> & {
15
15
  hasErrorBoundary: boolean;
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * React Router v0.0.0-experimental-7f486334
2
+ * React Router v0.0.0-experimental-b24023f3
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
@@ -9,7 +9,7 @@
9
9
  * @license MIT
10
10
  */
11
11
  import * as React from 'react';
12
- import { UNSAFE_invariant, joinPaths, matchPath, UNSAFE_getPathContributingMatches, UNSAFE_warning, resolveTo, parsePath, matchRoutes, Action, UNSAFE_convertRouteMatchToUiMatch, stripBasename, IDLE_BLOCKER, isRouteErrorResponse, createMemoryHistory, AbortedDeferredError, createRouter } from '@remix-run/router';
12
+ import { UNSAFE_invariant, joinPaths, matchPath, UNSAFE_getResolveToMatches, UNSAFE_warning, resolveTo, parsePath, matchRoutes, Action, UNSAFE_convertRouteMatchToUiMatch, stripBasename, IDLE_BLOCKER, isRouteErrorResponse, createMemoryHistory, AbortedDeferredError, createRouter } from '@remix-run/router';
13
13
  export { AbortedDeferredError, Action as NavigationType, createPath, defer, generatePath, isRouteErrorResponse, json, matchPath, matchRoutes, parsePath, redirect, redirectDocument, resolvePath } from '@remix-run/router';
14
14
 
15
15
  function _extends() {
@@ -212,7 +212,7 @@ function useNavigateUnstable() {
212
212
  let {
213
213
  pathname: locationPathname
214
214
  } = useLocation();
215
- let routePathnamesJson = JSON.stringify(UNSAFE_getPathContributingMatches(matches).map(match => match.pathnameBase));
215
+ let routePathnamesJson = JSON.stringify(UNSAFE_getResolveToMatches(matches));
216
216
  let activeRef = React.useRef(false);
217
217
  useIsomorphicLayoutEffect(() => {
218
218
  activeRef.current = true;
@@ -301,10 +301,7 @@ function useResolvedPath(to, _temp2) {
301
301
  let {
302
302
  pathname: locationPathname
303
303
  } = useLocation();
304
-
305
- // Use the full pathname for the leaf match so we include splat values
306
- // for "." links
307
- let routePathnamesJson = JSON.stringify(UNSAFE_getPathContributingMatches(matches).map((match, idx) => idx === matches.length - 1 ? match.pathname : match.pathnameBase));
304
+ let routePathnamesJson = JSON.stringify(UNSAFE_getResolveToMatches(matches));
308
305
  return React.useMemo(() => resolveTo(to, JSON.parse(routePathnamesJson), locationPathname, relative === "path"), [to, routePathnamesJson, locationPathname, relative]);
309
306
  }
310
307
 
@@ -321,7 +318,7 @@ function useRoutes(routes, locationArg) {
321
318
  }
322
319
 
323
320
  // Internal implementation with accept optional param for RouterProvider usage
324
- function useRoutesImpl(routes, locationArg, dataRouterState) {
321
+ function useRoutesImpl(routes, locationArg, dataRouterState, future) {
325
322
  !useInRouterContext() ? process.env.NODE_ENV !== "production" ? UNSAFE_invariant(false, // TODO: This error is probably because they somehow have 2 versions of the
326
323
  // router loaded. We can help them understand how to avoid that.
327
324
  "useRoutes() may be used only in the context of a <Router> component.") : UNSAFE_invariant(false) : void 0;
@@ -387,7 +384,7 @@ function useRoutesImpl(routes, locationArg, dataRouterState) {
387
384
  pathnameBase: match.pathnameBase === "/" ? parentPathnameBase : joinPaths([parentPathnameBase,
388
385
  // Re-encode pathnames that were decoded inside matchRoutes
389
386
  navigator.encodeLocation ? navigator.encodeLocation(match.pathnameBase).pathname : match.pathnameBase])
390
- })), parentMatches, dataRouterState);
387
+ })), parentMatches, dataRouterState, future);
391
388
 
392
389
  // When a user passes in a `locationArg`, the associated routes need to
393
390
  // be wrapped in a new `LocationContext.Provider` in order for `useLocation`
@@ -509,7 +506,7 @@ function RenderedRoute(_ref) {
509
506
  value: routeContext
510
507
  }, children);
511
508
  }
512
- function _renderMatches(matches, parentMatches, dataRouterState) {
509
+ function _renderMatches(matches, parentMatches, dataRouterState, future) {
513
510
  var _dataRouterState2;
514
511
  if (parentMatches === void 0) {
515
512
  parentMatches = [];
@@ -517,6 +514,9 @@ function _renderMatches(matches, parentMatches, dataRouterState) {
517
514
  if (dataRouterState === void 0) {
518
515
  dataRouterState = null;
519
516
  }
517
+ if (future === void 0) {
518
+ future = null;
519
+ }
520
520
  if (matches == null) {
521
521
  var _dataRouterState;
522
522
  if ((_dataRouterState = dataRouterState) != null && _dataRouterState.errors) {
@@ -536,18 +536,63 @@ function _renderMatches(matches, parentMatches, dataRouterState) {
536
536
  !(errorIndex >= 0) ? process.env.NODE_ENV !== "production" ? UNSAFE_invariant(false, "Could not find a matching route for errors on route IDs: " + Object.keys(errors).join(",")) : UNSAFE_invariant(false) : void 0;
537
537
  renderedMatches = renderedMatches.slice(0, Math.min(renderedMatches.length, errorIndex + 1));
538
538
  }
539
+
540
+ // If we're in a partial hydration mode, detect if we need to render down to
541
+ // a given Fallback while we load the rest of the hydration data
542
+ let renderFallback = false;
543
+ let fallbackIndex = -1;
544
+ if (dataRouterState && future && future.v7_partialHydration) {
545
+ for (let i = 0; i < renderedMatches.length; i++) {
546
+ let match = renderedMatches[i];
547
+ // Track the deepest fallback up until the first route without data
548
+ if (match.route.Fallback || match.route.fallbackElement) {
549
+ fallbackIndex = i;
550
+ }
551
+ if (match.route.loader && match.route.id && dataRouterState.loaderData[match.route.id] === undefined && (!dataRouterState.errors || dataRouterState.errors[match.route.id] === undefined)) {
552
+ // TODO:
553
+ // TODO: Add unit tests for this error flow!
554
+ // TODO:
555
+
556
+ // We found the first route without data/errors which means it's loader
557
+ // still needs to run. Flag that we need to render a fallback and
558
+ // render up until the appropriate fallback
559
+ renderFallback = true;
560
+ if (fallbackIndex >= 0) {
561
+ renderedMatches = renderedMatches.slice(0, fallbackIndex + 1);
562
+ } else {
563
+ renderedMatches = [renderedMatches[0]];
564
+ }
565
+ break;
566
+ }
567
+ }
568
+ }
539
569
  return renderedMatches.reduceRight((outlet, match, index) => {
540
- let error = match.route.id ? errors == null ? void 0 : errors[match.route.id] : null;
541
- // Only data routers handle errors
570
+ // Only data routers handle errors/fallbacks
571
+ let error;
572
+ let fallback = false;
542
573
  let errorElement = null;
574
+ let fallbackElement = null;
543
575
  if (dataRouterState) {
576
+ error = errors && match.route.id ? errors[match.route.id] : null;
544
577
  errorElement = match.route.errorElement || defaultErrorElement;
578
+ if (renderFallback) {
579
+ if (fallbackIndex < 0 && index === 0) {
580
+ warningOnce("route-fallback", false, "No `Fallback` element provided to render during initial hydration");
581
+ fallback = true;
582
+ fallbackElement = null;
583
+ } else if (fallbackIndex === index) {
584
+ fallback = true;
585
+ fallbackElement = match.route.fallbackElement || null;
586
+ }
587
+ }
545
588
  }
546
589
  let matches = parentMatches.concat(renderedMatches.slice(0, index + 1));
547
590
  let getChildren = () => {
548
591
  let children;
549
592
  if (error) {
550
593
  children = errorElement;
594
+ } else if (fallback) {
595
+ children = fallbackElement;
551
596
  } else if (match.route.Component) {
552
597
  // Note: This is a de-optimized path since React won't re-use the
553
598
  // ReactElement since it's identity changes with each new
@@ -701,9 +746,8 @@ function useRouteLoaderData(routeId) {
701
746
  */
702
747
  function useActionData() {
703
748
  let state = useDataRouterState(DataRouterStateHook.UseActionData);
704
- let route = React.useContext(RouteContext);
705
- !route ? process.env.NODE_ENV !== "production" ? UNSAFE_invariant(false, "useActionData must be used inside a RouteContext") : UNSAFE_invariant(false) : void 0;
706
- return Object.values((state == null ? void 0 : state.actionData) || {})[0];
749
+ let routeId = useCurrentRouteId(DataRouterStateHook.UseLoaderData);
750
+ return state.actionData ? state.actionData[routeId] : undefined;
707
751
  }
708
752
 
709
753
  /**
@@ -895,6 +939,11 @@ function RouterProvider(_ref) {
895
939
  // Need to use a layout effect here so we are subscribed early enough to
896
940
  // pick up on any render-driven redirects/navigations (useEffect/<Navigate>)
897
941
  React.useLayoutEffect(() => router.subscribe(setState), [router, setState]);
942
+ React.useEffect(() => {
943
+ process.env.NODE_ENV !== "production" ? UNSAFE_warning(fallbackElement == null || !router.future.v7_partialHydration, "`<RouterProvider fallbackElement>` is deprecated when using `v7_partialHydration`") : void 0;
944
+ // Only log this once on initial mount
945
+ // eslint-disable-next-line react-hooks/exhaustive-deps
946
+ }, []);
898
947
  let navigator = React.useMemo(() => {
899
948
  return {
900
949
  createHref: router.createHref,
@@ -936,15 +985,17 @@ function RouterProvider(_ref) {
936
985
  navigator: navigator
937
986
  }, state.initialized ? /*#__PURE__*/React.createElement(DataRoutes, {
938
987
  routes: router.routes,
988
+ future: router.future,
939
989
  state: state
940
990
  }) : fallbackElement))), null);
941
991
  }
942
992
  function DataRoutes(_ref2) {
943
993
  let {
944
994
  routes,
995
+ future,
945
996
  state
946
997
  } = _ref2;
947
- return useRoutesImpl(routes, undefined, state);
998
+ return useRoutesImpl(routes, undefined, state, future);
948
999
  }
949
1000
  /**
950
1001
  * A `<Router>` that stores all entries in memory.
@@ -1017,7 +1068,7 @@ function Navigate(_ref4) {
1017
1068
 
1018
1069
  // Resolve the path outside of the effect so that when effects run twice in
1019
1070
  // StrictMode they navigate to the same place
1020
- let path = resolveTo(to, UNSAFE_getPathContributingMatches(matches).map(match => match.pathnameBase), locationPathname, relative === "path");
1071
+ let path = resolveTo(to, UNSAFE_getResolveToMatches(matches), locationPathname, relative === "path");
1021
1072
  let jsonPath = JSON.stringify(path);
1022
1073
  React.useEffect(() => navigate(JSON.parse(jsonPath), {
1023
1074
  replace,
@@ -1321,6 +1372,17 @@ function mapRouteProperties(route) {
1321
1372
  Component: undefined
1322
1373
  });
1323
1374
  }
1375
+ if (route.Fallback) {
1376
+ if (process.env.NODE_ENV !== "production") {
1377
+ if (route.fallbackElement) {
1378
+ process.env.NODE_ENV !== "production" ? UNSAFE_warning(false, "You should not include both `Fallback` and `fallbackElement` on your route - " + "`Fallback` will be used.") : void 0;
1379
+ }
1380
+ }
1381
+ Object.assign(updates, {
1382
+ fallbackElement: /*#__PURE__*/React.createElement(route.Fallback),
1383
+ Fallback: undefined
1384
+ });
1385
+ }
1324
1386
  if (route.ErrorBoundary) {
1325
1387
  if (process.env.NODE_ENV !== "production") {
1326
1388
  if (route.errorElement) {