react-router 6.4.0-pre.8 → 6.4.0
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 +16 -35
- package/dist/index.d.ts +16 -10
- package/dist/index.js +344 -116
- package/dist/index.js.map +1 -1
- package/dist/lib/components.d.ts +30 -16
- package/dist/lib/context.d.ts +25 -9
- package/dist/lib/hooks.d.ts +24 -12
- package/dist/lib/use-sync-external-store-shim/index.d.ts +2 -1
- package/dist/main.js +1 -1
- package/dist/react-router.development.js +318 -106
- package/dist/react-router.development.js.map +1 -1
- package/dist/react-router.production.min.js +2 -2
- package/dist/react-router.production.min.js.map +1 -1
- package/dist/umd/react-router.development.js +357 -115
- package/dist/umd/react-router.development.js.map +1 -1
- package/dist/umd/react-router.production.min.js +2 -2
- package/dist/umd/react-router.production.min.js.map +1 -1
- package/package.json +7 -4
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* React Router v6.4.0
|
|
2
|
+
* React Router v6.4.0
|
|
3
3
|
*
|
|
4
4
|
* Copyright (c) Remix Software Inc.
|
|
5
5
|
*
|
|
@@ -8,8 +8,8 @@
|
|
|
8
8
|
*
|
|
9
9
|
* @license MIT
|
|
10
10
|
*/
|
|
11
|
-
import { invariant, resolveTo,
|
|
12
|
-
export { Action as NavigationType, createPath, generatePath, isRouteErrorResponse, json, matchPath, matchRoutes, parsePath, redirect, resolvePath } from '@remix-run/router';
|
|
11
|
+
import { invariant, resolveTo, joinPaths, matchPath, warning, parsePath, matchRoutes, Action, isRouteErrorResponse, createMemoryHistory, stripBasename, AbortedDeferredError, createRouter } from '@remix-run/router';
|
|
12
|
+
export { AbortedDeferredError, Action as NavigationType, createPath, defer, generatePath, isRouteErrorResponse, json, matchPath, matchRoutes, parsePath, redirect, resolvePath } from '@remix-run/router';
|
|
13
13
|
import * as React from 'react';
|
|
14
14
|
|
|
15
15
|
/**
|
|
@@ -188,8 +188,13 @@ function useSyncExternalStore$1(subscribe, getSnapshot, getServerSnapshot) {
|
|
|
188
188
|
const canUseDOM = !!(typeof window !== "undefined" && typeof window.document !== "undefined" && typeof window.document.createElement !== "undefined");
|
|
189
189
|
const isServerEnvironment = !canUseDOM;
|
|
190
190
|
const shim = isServerEnvironment ? useSyncExternalStore$1 : useSyncExternalStore$2;
|
|
191
|
-
const useSyncExternalStore = "useSyncExternalStore" in React ?
|
|
192
|
-
|
|
191
|
+
const useSyncExternalStore = "useSyncExternalStore" in React ? (module => module.useSyncExternalStore)(React) : shim;
|
|
192
|
+
|
|
193
|
+
const DataStaticRouterContext = /*#__PURE__*/React.createContext(null);
|
|
194
|
+
|
|
195
|
+
{
|
|
196
|
+
DataStaticRouterContext.displayName = "DataStaticRouterContext";
|
|
197
|
+
}
|
|
193
198
|
|
|
194
199
|
const DataRouterContext = /*#__PURE__*/React.createContext(null);
|
|
195
200
|
|
|
@@ -203,6 +208,12 @@ const DataRouterStateContext = /*#__PURE__*/React.createContext(null);
|
|
|
203
208
|
DataRouterStateContext.displayName = "DataRouterState";
|
|
204
209
|
}
|
|
205
210
|
|
|
211
|
+
const AwaitContext = /*#__PURE__*/React.createContext(null);
|
|
212
|
+
|
|
213
|
+
{
|
|
214
|
+
AwaitContext.displayName = "Await";
|
|
215
|
+
}
|
|
216
|
+
|
|
206
217
|
const NavigationContext = /*#__PURE__*/React.createContext(null);
|
|
207
218
|
|
|
208
219
|
{
|
|
@@ -237,7 +248,9 @@ const RouteErrorContext = /*#__PURE__*/React.createContext(null);
|
|
|
237
248
|
* @see https://reactrouter.com/docs/en/v6/hooks/use-href
|
|
238
249
|
*/
|
|
239
250
|
|
|
240
|
-
function useHref(to
|
|
251
|
+
function useHref(to, {
|
|
252
|
+
relative
|
|
253
|
+
} = {}) {
|
|
241
254
|
!useInRouterContext() ? invariant(false, // TODO: This error is probably because they somehow have 2 versions of the
|
|
242
255
|
// router loaded. We can help them understand how to avoid that.
|
|
243
256
|
`useHref() may be used only in the context of a <Router> component.`) : void 0;
|
|
@@ -249,23 +262,16 @@ function useHref(to) {
|
|
|
249
262
|
hash,
|
|
250
263
|
pathname,
|
|
251
264
|
search
|
|
252
|
-
} = useResolvedPath(to
|
|
253
|
-
|
|
265
|
+
} = useResolvedPath(to, {
|
|
266
|
+
relative
|
|
267
|
+
});
|
|
268
|
+
let joinedPathname = pathname; // If we're operating within a basename, prepend it to the pathname prior
|
|
269
|
+
// to creating the href. If this is a root navigation, then just use the raw
|
|
270
|
+
// basename which allows the basename to have full control over the presence
|
|
271
|
+
// of a trailing slash on root links
|
|
254
272
|
|
|
255
273
|
if (basename !== "/") {
|
|
256
|
-
|
|
257
|
-
// already have one and this wasn't specifically a route to "". This
|
|
258
|
-
// allows folks to control the trailing slash behavior when using a basename
|
|
259
|
-
|
|
260
|
-
let appendSlash = !basename.endsWith("/") && to !== "" && to?.pathname !== "" && toPathname != null && toPathname.endsWith("/");
|
|
261
|
-
|
|
262
|
-
if (pathname !== "/") {
|
|
263
|
-
joinedPathname = joinPaths([basename, pathname]);
|
|
264
|
-
} else if (appendSlash) {
|
|
265
|
-
joinedPathname = basename + "/";
|
|
266
|
-
} else {
|
|
267
|
-
joinedPathname = basename;
|
|
268
|
-
}
|
|
274
|
+
joinedPathname = pathname === "/" ? basename : joinPaths([basename, pathname]);
|
|
269
275
|
}
|
|
270
276
|
|
|
271
277
|
return navigator.createHref({
|
|
@@ -388,14 +394,13 @@ function useNavigate() {
|
|
|
388
394
|
return;
|
|
389
395
|
}
|
|
390
396
|
|
|
391
|
-
let path = resolveTo(to, JSON.parse(routePathnamesJson), locationPathname);
|
|
397
|
+
let path = resolveTo(to, JSON.parse(routePathnamesJson), locationPathname, options.relative === "path"); // If we're operating within a basename, prepend it to the pathname prior
|
|
398
|
+
// to handing off to history. If this is a root navigation, then we
|
|
399
|
+
// navigate to the raw basename which allows the basename to have full
|
|
400
|
+
// control over the presence of a trailing slash on root links
|
|
392
401
|
|
|
393
402
|
if (basename !== "/") {
|
|
394
|
-
|
|
395
|
-
// the user control over trailing slash behavior
|
|
396
|
-
let toPath = typeof to === "string" ? parsePath(to) : to;
|
|
397
|
-
let isBlankPath = toPath.pathname == null || toPath.pathname === "";
|
|
398
|
-
path.pathname = isBlankPath ? basename : joinPaths([basename, path.pathname]);
|
|
403
|
+
path.pathname = path.pathname === "/" ? basename : joinPaths([basename, path.pathname]);
|
|
399
404
|
}
|
|
400
405
|
|
|
401
406
|
(!!options.replace ? navigator.replace : navigator.push)(path, options.state, options);
|
|
@@ -450,7 +455,9 @@ function useParams() {
|
|
|
450
455
|
* @see https://reactrouter.com/docs/en/v6/hooks/use-resolved-path
|
|
451
456
|
*/
|
|
452
457
|
|
|
453
|
-
function useResolvedPath(to
|
|
458
|
+
function useResolvedPath(to, {
|
|
459
|
+
relative
|
|
460
|
+
} = {}) {
|
|
454
461
|
let {
|
|
455
462
|
matches
|
|
456
463
|
} = React.useContext(RouteContext);
|
|
@@ -458,7 +465,7 @@ function useResolvedPath(to) {
|
|
|
458
465
|
pathname: locationPathname
|
|
459
466
|
} = useLocation();
|
|
460
467
|
let routePathnamesJson = JSON.stringify(getPathContributingMatches(matches).map(match => match.pathnameBase));
|
|
461
|
-
return React.useMemo(() => resolveTo(to, JSON.parse(routePathnamesJson), locationPathname), [to, routePathnamesJson, locationPathname]);
|
|
468
|
+
return React.useMemo(() => resolveTo(to, JSON.parse(routePathnamesJson), locationPathname, relative === "path"), [to, routePathnamesJson, locationPathname, relative]);
|
|
462
469
|
}
|
|
463
470
|
/**
|
|
464
471
|
* Returns the element of the route that matched the current location, prepared
|
|
@@ -530,16 +537,38 @@ function useRoutes(routes, locationArg) {
|
|
|
530
537
|
warning(matches == null || matches[matches.length - 1].route.element !== undefined, `Matched leaf route at location "${location.pathname}${location.search}${location.hash}" does not have an element. ` + `This means it will render an <Outlet /> with a null value by default resulting in an "empty" page.`) ;
|
|
531
538
|
}
|
|
532
539
|
|
|
533
|
-
|
|
540
|
+
let renderedMatches = _renderMatches(matches && matches.map(match => Object.assign({}, match, {
|
|
534
541
|
params: Object.assign({}, parentParams, match.params),
|
|
535
542
|
pathname: joinPaths([parentPathnameBase, match.pathname]),
|
|
536
543
|
pathnameBase: match.pathnameBase === "/" ? parentPathnameBase : joinPaths([parentPathnameBase, match.pathnameBase])
|
|
537
|
-
})), parentMatches, dataRouterStateContext || undefined);
|
|
544
|
+
})), parentMatches, dataRouterStateContext || undefined); // When a user passes in a `locationArg`, the associated routes need to
|
|
545
|
+
// be wrapped in a new `LocationContext.Provider` in order for `useLocation`
|
|
546
|
+
// to use the scoped location instead of the global location.
|
|
547
|
+
|
|
548
|
+
|
|
549
|
+
if (locationArg) {
|
|
550
|
+
return /*#__PURE__*/React.createElement(LocationContext.Provider, {
|
|
551
|
+
value: {
|
|
552
|
+
location: {
|
|
553
|
+
pathname: "/",
|
|
554
|
+
search: "",
|
|
555
|
+
hash: "",
|
|
556
|
+
state: null,
|
|
557
|
+
key: "default",
|
|
558
|
+
...location
|
|
559
|
+
},
|
|
560
|
+
navigationType: Action.Pop
|
|
561
|
+
}
|
|
562
|
+
}, renderedMatches);
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
return renderedMatches;
|
|
538
566
|
}
|
|
539
567
|
|
|
540
568
|
function DefaultErrorElement() {
|
|
541
569
|
let error = useRouteError();
|
|
542
|
-
let message = isRouteErrorResponse(error) ? `${error.status} ${error.statusText}` : error
|
|
570
|
+
let message = isRouteErrorResponse(error) ? `${error.status} ${error.statusText}` : error instanceof Error ? error.message : JSON.stringify(error);
|
|
571
|
+
let stack = error instanceof Error ? error.stack : null;
|
|
543
572
|
let lightgrey = "rgba(200,200,200, 0.5)";
|
|
544
573
|
let preStyles = {
|
|
545
574
|
padding: "0.5rem",
|
|
@@ -553,9 +582,9 @@ function DefaultErrorElement() {
|
|
|
553
582
|
style: {
|
|
554
583
|
fontStyle: "italic"
|
|
555
584
|
}
|
|
556
|
-
}, message),
|
|
585
|
+
}, message), stack ? /*#__PURE__*/React.createElement("pre", {
|
|
557
586
|
style: preStyles
|
|
558
|
-
},
|
|
587
|
+
}, stack) : null, /*#__PURE__*/React.createElement("p", null, "\uD83D\uDCBF Hey developer \uD83D\uDC4B"), /*#__PURE__*/React.createElement("p", null, "You can provide a way better UX than this when your app throws errors by providing your own\u00A0", /*#__PURE__*/React.createElement("code", {
|
|
559
588
|
style: codeStyles
|
|
560
589
|
}, "errorElement"), " props on\u00A0", /*#__PURE__*/React.createElement("code", {
|
|
561
590
|
style: codeStyles
|
|
@@ -615,6 +644,24 @@ class RenderErrorBoundary extends React.Component {
|
|
|
615
644
|
}
|
|
616
645
|
|
|
617
646
|
}
|
|
647
|
+
|
|
648
|
+
function RenderedRoute({
|
|
649
|
+
routeContext,
|
|
650
|
+
match,
|
|
651
|
+
children
|
|
652
|
+
}) {
|
|
653
|
+
let dataStaticRouterContext = React.useContext(DataStaticRouterContext); // Track how deep we got in our render pass to emulate SSR componentDidCatch
|
|
654
|
+
// in a DataStaticRouter
|
|
655
|
+
|
|
656
|
+
if (dataStaticRouterContext && match.route.errorElement) {
|
|
657
|
+
dataStaticRouterContext._deepestRenderedBoundaryId = match.route.id;
|
|
658
|
+
}
|
|
659
|
+
|
|
660
|
+
return /*#__PURE__*/React.createElement(RouteContext.Provider, {
|
|
661
|
+
value: routeContext
|
|
662
|
+
}, children);
|
|
663
|
+
}
|
|
664
|
+
|
|
618
665
|
function _renderMatches(matches, parentMatches = [], dataRouterState) {
|
|
619
666
|
if (matches == null) {
|
|
620
667
|
if (dataRouterState?.errors) {
|
|
@@ -641,13 +688,13 @@ function _renderMatches(matches, parentMatches = [], dataRouterState) {
|
|
|
641
688
|
|
|
642
689
|
let errorElement = dataRouterState ? match.route.errorElement || /*#__PURE__*/React.createElement(DefaultErrorElement, null) : null;
|
|
643
690
|
|
|
644
|
-
let getChildren = () => /*#__PURE__*/React.createElement(
|
|
645
|
-
|
|
646
|
-
|
|
691
|
+
let getChildren = () => /*#__PURE__*/React.createElement(RenderedRoute, {
|
|
692
|
+
match: match,
|
|
693
|
+
routeContext: {
|
|
647
694
|
outlet,
|
|
648
695
|
matches: parentMatches.concat(renderedMatches.slice(0, index + 1))
|
|
649
696
|
}
|
|
650
|
-
}); // Only wrap in an error boundary within data router usages when we have an
|
|
697
|
+
}, error ? errorElement : match.route.element !== undefined ? match.route.element : outlet); // Only wrap in an error boundary within data router usages when we have an
|
|
651
698
|
// errorElement on this route. Otherwise let it bubble up to an ancestor
|
|
652
699
|
// errorElement
|
|
653
700
|
|
|
@@ -674,7 +721,7 @@ var DataRouterHook;
|
|
|
674
721
|
|
|
675
722
|
function useDataRouterState(hookName) {
|
|
676
723
|
let state = React.useContext(DataRouterStateContext);
|
|
677
|
-
!state ? invariant(false, `${hookName} must be used within a
|
|
724
|
+
!state ? invariant(false, `${hookName} must be used within a DataRouterStateContext`) : void 0;
|
|
678
725
|
return state;
|
|
679
726
|
}
|
|
680
727
|
/**
|
|
@@ -693,11 +740,11 @@ function useNavigation() {
|
|
|
693
740
|
*/
|
|
694
741
|
|
|
695
742
|
function useRevalidator() {
|
|
696
|
-
let
|
|
697
|
-
!
|
|
743
|
+
let dataRouterContext = React.useContext(DataRouterContext);
|
|
744
|
+
!dataRouterContext ? invariant(false, `useRevalidator must be used within a DataRouterContext`) : void 0;
|
|
698
745
|
let state = useDataRouterState(DataRouterHook.UseRevalidator);
|
|
699
746
|
return {
|
|
700
|
-
revalidate: router.revalidate,
|
|
747
|
+
revalidate: dataRouterContext.router.revalidate,
|
|
701
748
|
state: state.revalidation
|
|
702
749
|
};
|
|
703
750
|
}
|
|
@@ -715,7 +762,10 @@ function useMatches() {
|
|
|
715
762
|
let {
|
|
716
763
|
pathname,
|
|
717
764
|
params
|
|
718
|
-
} = match;
|
|
765
|
+
} = match; // Note: This structure matches that created by createUseMatchesMatch
|
|
766
|
+
// in the @remix-run/router , so if you change this please also change
|
|
767
|
+
// that :) Eventually we'll DRY this up
|
|
768
|
+
|
|
719
769
|
return {
|
|
720
770
|
id: match.route.id,
|
|
721
771
|
pathname,
|
|
@@ -777,6 +827,22 @@ function useRouteError() {
|
|
|
777
827
|
|
|
778
828
|
return state.errors?.[thisRoute.route.id];
|
|
779
829
|
}
|
|
830
|
+
/**
|
|
831
|
+
* Returns the happy-path data from the nearest ancestor <Await /> value
|
|
832
|
+
*/
|
|
833
|
+
|
|
834
|
+
function useAsyncValue() {
|
|
835
|
+
let value = React.useContext(AwaitContext);
|
|
836
|
+
return value?._data;
|
|
837
|
+
}
|
|
838
|
+
/**
|
|
839
|
+
* Returns the error from the nearest ancestor <Await /> value
|
|
840
|
+
*/
|
|
841
|
+
|
|
842
|
+
function useAsyncError() {
|
|
843
|
+
let value = React.useContext(AwaitContext);
|
|
844
|
+
return value?._error;
|
|
845
|
+
}
|
|
780
846
|
const alreadyWarned = {};
|
|
781
847
|
|
|
782
848
|
function warningOnce(key, cond, message) {
|
|
@@ -786,80 +852,51 @@ function warningOnce(key, cond, message) {
|
|
|
786
852
|
}
|
|
787
853
|
}
|
|
788
854
|
|
|
789
|
-
// to avoid issues w.r.t. dual initialization fetches in concurrent rendering.
|
|
790
|
-
// Data router apps are expected to have a static route tree and are not intended
|
|
791
|
-
// to be unmounted/remounted at runtime.
|
|
792
|
-
|
|
793
|
-
let routerSingleton;
|
|
794
855
|
/**
|
|
795
|
-
*
|
|
856
|
+
* Given a Remix Router instance, render the appropriate UI
|
|
796
857
|
*/
|
|
797
858
|
|
|
798
|
-
function
|
|
799
|
-
children,
|
|
859
|
+
function RouterProvider({
|
|
800
860
|
fallbackElement,
|
|
801
|
-
|
|
802
|
-
createRouter
|
|
861
|
+
router
|
|
803
862
|
}) {
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
let state = useSyncExternalStore(router.subscribe, () => router.state);
|
|
863
|
+
// Sync router state to our component state to force re-renders
|
|
864
|
+
let state = useSyncExternalStore(router.subscribe, () => router.state, // We have to provide this so React@18 doesn't complain during hydration,
|
|
865
|
+
// but we pass our serialized hydration data into the router so state here
|
|
866
|
+
// is already synced with what the server saw
|
|
867
|
+
() => router.state);
|
|
811
868
|
let navigator = React.useMemo(() => {
|
|
812
869
|
return {
|
|
813
870
|
createHref: router.createHref,
|
|
814
871
|
go: n => router.navigate(n),
|
|
815
872
|
push: (to, state, opts) => router.navigate(to, {
|
|
816
873
|
state,
|
|
817
|
-
|
|
874
|
+
preventScrollReset: opts?.preventScrollReset
|
|
818
875
|
}),
|
|
819
876
|
replace: (to, state, opts) => router.navigate(to, {
|
|
820
877
|
replace: true,
|
|
821
878
|
state,
|
|
822
|
-
|
|
879
|
+
preventScrollReset: opts?.preventScrollReset
|
|
823
880
|
})
|
|
824
881
|
};
|
|
825
882
|
}, [router]);
|
|
826
|
-
|
|
827
|
-
if (!state.initialized) {
|
|
828
|
-
return /*#__PURE__*/React.createElement(React.Fragment, null, fallbackElement);
|
|
829
|
-
}
|
|
830
|
-
|
|
883
|
+
let basename = router.basename || "/";
|
|
831
884
|
return /*#__PURE__*/React.createElement(DataRouterContext.Provider, {
|
|
832
|
-
value:
|
|
885
|
+
value: {
|
|
886
|
+
router,
|
|
887
|
+
navigator,
|
|
888
|
+
static: false,
|
|
889
|
+
// Do we need this?
|
|
890
|
+
basename
|
|
891
|
+
}
|
|
833
892
|
}, /*#__PURE__*/React.createElement(DataRouterStateContext.Provider, {
|
|
834
893
|
value: state
|
|
835
894
|
}, /*#__PURE__*/React.createElement(Router, {
|
|
836
|
-
|
|
837
|
-
|
|
895
|
+
basename: router.basename,
|
|
896
|
+
location: router.state.location,
|
|
897
|
+
navigationType: router.state.historyAction,
|
|
838
898
|
navigator: navigator
|
|
839
|
-
}, /*#__PURE__*/React.createElement(
|
|
840
|
-
routes: routes,
|
|
841
|
-
children: children
|
|
842
|
-
}))));
|
|
843
|
-
}
|
|
844
|
-
function DataMemoryRouter({
|
|
845
|
-
children,
|
|
846
|
-
initialEntries,
|
|
847
|
-
initialIndex,
|
|
848
|
-
hydrationData,
|
|
849
|
-
fallbackElement,
|
|
850
|
-
routes
|
|
851
|
-
}) {
|
|
852
|
-
return useRenderDataRouter({
|
|
853
|
-
children,
|
|
854
|
-
fallbackElement,
|
|
855
|
-
routes,
|
|
856
|
-
createRouter: routes => createMemoryRouter({
|
|
857
|
-
initialEntries,
|
|
858
|
-
initialIndex,
|
|
859
|
-
routes,
|
|
860
|
-
hydrationData
|
|
861
|
-
})
|
|
862
|
-
});
|
|
899
|
+
}, router.state.initialized ? /*#__PURE__*/React.createElement(Routes, null) : fallbackElement)));
|
|
863
900
|
}
|
|
864
901
|
/**
|
|
865
902
|
* A <Router> that stores all entries in memory.
|
|
@@ -910,17 +947,27 @@ function MemoryRouter({
|
|
|
910
947
|
function Navigate({
|
|
911
948
|
to,
|
|
912
949
|
replace,
|
|
913
|
-
state
|
|
950
|
+
state,
|
|
951
|
+
relative
|
|
914
952
|
}) {
|
|
915
953
|
!useInRouterContext() ? invariant(false, // TODO: This error is probably because they somehow have 2 versions of
|
|
916
954
|
// the router loaded. We can help them understand how to avoid that.
|
|
917
955
|
`<Navigate> may be used only in the context of a <Router> component.`) : void 0;
|
|
918
956
|
warning(!React.useContext(NavigationContext).static, `<Navigate> must not be used on the initial render in a <StaticRouter>. ` + `This is a no-op, but you should modify your code so the <Navigate> is ` + `only ever rendered in response to some user interaction or state change.`) ;
|
|
957
|
+
let dataRouterState = React.useContext(DataRouterStateContext);
|
|
919
958
|
let navigate = useNavigate();
|
|
920
959
|
React.useEffect(() => {
|
|
960
|
+
// Avoid kicking off multiple navigations if we're in the middle of a
|
|
961
|
+
// data-router navigation, since components get re-rendered when we enter
|
|
962
|
+
// a submitting/loading state
|
|
963
|
+
if (dataRouterState && dataRouterState.navigation.state !== "idle") {
|
|
964
|
+
return;
|
|
965
|
+
}
|
|
966
|
+
|
|
921
967
|
navigate(to, {
|
|
922
968
|
replace,
|
|
923
|
-
state
|
|
969
|
+
state,
|
|
970
|
+
relative
|
|
924
971
|
});
|
|
925
972
|
});
|
|
926
973
|
return null;
|
|
@@ -1024,21 +1071,151 @@ function Routes({
|
|
|
1024
1071
|
children,
|
|
1025
1072
|
location
|
|
1026
1073
|
}) {
|
|
1027
|
-
|
|
1074
|
+
let dataRouterContext = React.useContext(DataRouterContext); // When in a DataRouterContext _without_ children, we use the router routes
|
|
1075
|
+
// directly. If we have children, then we're in a descendant tree and we
|
|
1076
|
+
// need to use child routes.
|
|
1077
|
+
|
|
1078
|
+
let routes = dataRouterContext && !children ? dataRouterContext.router.routes : createRoutesFromChildren(children);
|
|
1079
|
+
return useRoutes(routes, location);
|
|
1028
1080
|
}
|
|
1029
1081
|
/**
|
|
1030
|
-
*
|
|
1031
|
-
*
|
|
1032
|
-
* instead of using JSX children. Extracted to it's own component to avoid
|
|
1033
|
-
* conditional usage of `useRoutes` if we have to render a `fallbackElement`
|
|
1082
|
+
* Component to use for rendering lazily loaded data from returning defer()
|
|
1083
|
+
* in a loader function
|
|
1034
1084
|
*/
|
|
1035
1085
|
|
|
1036
|
-
function
|
|
1086
|
+
function Await({
|
|
1037
1087
|
children,
|
|
1038
|
-
|
|
1039
|
-
|
|
1088
|
+
errorElement,
|
|
1089
|
+
resolve
|
|
1040
1090
|
}) {
|
|
1041
|
-
return
|
|
1091
|
+
return /*#__PURE__*/React.createElement(AwaitErrorBoundary, {
|
|
1092
|
+
resolve: resolve,
|
|
1093
|
+
errorElement: errorElement
|
|
1094
|
+
}, /*#__PURE__*/React.createElement(ResolveAwait, null, children));
|
|
1095
|
+
}
|
|
1096
|
+
var AwaitRenderStatus;
|
|
1097
|
+
|
|
1098
|
+
(function (AwaitRenderStatus) {
|
|
1099
|
+
AwaitRenderStatus[AwaitRenderStatus["pending"] = 0] = "pending";
|
|
1100
|
+
AwaitRenderStatus[AwaitRenderStatus["success"] = 1] = "success";
|
|
1101
|
+
AwaitRenderStatus[AwaitRenderStatus["error"] = 2] = "error";
|
|
1102
|
+
})(AwaitRenderStatus || (AwaitRenderStatus = {}));
|
|
1103
|
+
|
|
1104
|
+
const neverSettledPromise = new Promise(() => {});
|
|
1105
|
+
|
|
1106
|
+
class AwaitErrorBoundary extends React.Component {
|
|
1107
|
+
constructor(props) {
|
|
1108
|
+
super(props);
|
|
1109
|
+
this.state = {
|
|
1110
|
+
error: null
|
|
1111
|
+
};
|
|
1112
|
+
}
|
|
1113
|
+
|
|
1114
|
+
static getDerivedStateFromError(error) {
|
|
1115
|
+
return {
|
|
1116
|
+
error
|
|
1117
|
+
};
|
|
1118
|
+
}
|
|
1119
|
+
|
|
1120
|
+
componentDidCatch(error, errorInfo) {
|
|
1121
|
+
console.error("<Await> caught the following error during render", error, errorInfo);
|
|
1122
|
+
}
|
|
1123
|
+
|
|
1124
|
+
render() {
|
|
1125
|
+
let {
|
|
1126
|
+
children,
|
|
1127
|
+
errorElement,
|
|
1128
|
+
resolve
|
|
1129
|
+
} = this.props;
|
|
1130
|
+
let promise = null;
|
|
1131
|
+
let status = AwaitRenderStatus.pending;
|
|
1132
|
+
|
|
1133
|
+
if (!(resolve instanceof Promise)) {
|
|
1134
|
+
// Didn't get a promise - provide as a resolved promise
|
|
1135
|
+
status = AwaitRenderStatus.success;
|
|
1136
|
+
promise = Promise.resolve();
|
|
1137
|
+
Object.defineProperty(promise, "_tracked", {
|
|
1138
|
+
get: () => true
|
|
1139
|
+
});
|
|
1140
|
+
Object.defineProperty(promise, "_data", {
|
|
1141
|
+
get: () => resolve
|
|
1142
|
+
});
|
|
1143
|
+
} else if (this.state.error) {
|
|
1144
|
+
// Caught a render error, provide it as a rejected promise
|
|
1145
|
+
status = AwaitRenderStatus.error;
|
|
1146
|
+
let renderError = this.state.error;
|
|
1147
|
+
promise = Promise.reject().catch(() => {}); // Avoid unhandled rejection warnings
|
|
1148
|
+
|
|
1149
|
+
Object.defineProperty(promise, "_tracked", {
|
|
1150
|
+
get: () => true
|
|
1151
|
+
});
|
|
1152
|
+
Object.defineProperty(promise, "_error", {
|
|
1153
|
+
get: () => renderError
|
|
1154
|
+
});
|
|
1155
|
+
} else if (resolve._tracked) {
|
|
1156
|
+
// Already tracked promise - check contents
|
|
1157
|
+
promise = resolve;
|
|
1158
|
+
status = promise._error !== undefined ? AwaitRenderStatus.error : promise._data !== undefined ? AwaitRenderStatus.success : AwaitRenderStatus.pending;
|
|
1159
|
+
} else {
|
|
1160
|
+
// Raw (untracked) promise - track it
|
|
1161
|
+
status = AwaitRenderStatus.pending;
|
|
1162
|
+
Object.defineProperty(resolve, "_tracked", {
|
|
1163
|
+
get: () => true
|
|
1164
|
+
});
|
|
1165
|
+
promise = resolve.then(data => Object.defineProperty(resolve, "_data", {
|
|
1166
|
+
get: () => data
|
|
1167
|
+
}), error => Object.defineProperty(resolve, "_error", {
|
|
1168
|
+
get: () => error
|
|
1169
|
+
}));
|
|
1170
|
+
}
|
|
1171
|
+
|
|
1172
|
+
if (status === AwaitRenderStatus.error && promise._error instanceof AbortedDeferredError) {
|
|
1173
|
+
// Freeze the UI by throwing a never resolved promise
|
|
1174
|
+
throw neverSettledPromise;
|
|
1175
|
+
}
|
|
1176
|
+
|
|
1177
|
+
if (status === AwaitRenderStatus.error && !errorElement) {
|
|
1178
|
+
// No errorElement, throw to the nearest route-level error boundary
|
|
1179
|
+
throw promise._error;
|
|
1180
|
+
}
|
|
1181
|
+
|
|
1182
|
+
if (status === AwaitRenderStatus.error) {
|
|
1183
|
+
// Render via our errorElement
|
|
1184
|
+
return /*#__PURE__*/React.createElement(AwaitContext.Provider, {
|
|
1185
|
+
value: promise,
|
|
1186
|
+
children: errorElement
|
|
1187
|
+
});
|
|
1188
|
+
}
|
|
1189
|
+
|
|
1190
|
+
if (status === AwaitRenderStatus.success) {
|
|
1191
|
+
// Render children with resolved value
|
|
1192
|
+
return /*#__PURE__*/React.createElement(AwaitContext.Provider, {
|
|
1193
|
+
value: promise,
|
|
1194
|
+
children: children
|
|
1195
|
+
});
|
|
1196
|
+
} // Throw to the suspense boundary
|
|
1197
|
+
|
|
1198
|
+
|
|
1199
|
+
throw promise;
|
|
1200
|
+
}
|
|
1201
|
+
|
|
1202
|
+
}
|
|
1203
|
+
/**
|
|
1204
|
+
* @private
|
|
1205
|
+
* Indirection to leverage useAsyncValue for a render-prop API on <Await>
|
|
1206
|
+
*/
|
|
1207
|
+
|
|
1208
|
+
|
|
1209
|
+
function ResolveAwait({
|
|
1210
|
+
children
|
|
1211
|
+
}) {
|
|
1212
|
+
let data = useAsyncValue();
|
|
1213
|
+
|
|
1214
|
+
if (typeof children === "function") {
|
|
1215
|
+
return children(data);
|
|
1216
|
+
}
|
|
1217
|
+
|
|
1218
|
+
return /*#__PURE__*/React.createElement(React.Fragment, null, children);
|
|
1042
1219
|
} ///////////////////////////////////////////////////////////////////////////////
|
|
1043
1220
|
// UTILS
|
|
1044
1221
|
///////////////////////////////////////////////////////////////////////////////
|
|
@@ -1078,6 +1255,7 @@ function createRoutesFromChildren(children, parentPath = []) {
|
|
|
1078
1255
|
loader: element.props.loader,
|
|
1079
1256
|
action: element.props.action,
|
|
1080
1257
|
errorElement: element.props.errorElement,
|
|
1258
|
+
hasErrorBoundary: element.props.errorElement != null,
|
|
1081
1259
|
shouldRevalidate: element.props.shouldRevalidate,
|
|
1082
1260
|
handle: element.props.handle
|
|
1083
1261
|
};
|
|
@@ -1097,6 +1275,40 @@ function createRoutesFromChildren(children, parentPath = []) {
|
|
|
1097
1275
|
function renderMatches(matches) {
|
|
1098
1276
|
return _renderMatches(matches);
|
|
1099
1277
|
}
|
|
1278
|
+
/**
|
|
1279
|
+
* @private
|
|
1280
|
+
* Walk the route tree and add hasErrorBoundary if it's not provided, so that
|
|
1281
|
+
* users providing manual route arrays can just specify errorElement
|
|
1282
|
+
*/
|
|
1283
|
+
|
|
1284
|
+
function enhanceManualRouteObjects(routes) {
|
|
1285
|
+
return routes.map(route => {
|
|
1286
|
+
let routeClone = { ...route
|
|
1287
|
+
};
|
|
1288
|
+
|
|
1289
|
+
if (routeClone.hasErrorBoundary == null) {
|
|
1290
|
+
routeClone.hasErrorBoundary = routeClone.errorElement != null;
|
|
1291
|
+
}
|
|
1292
|
+
|
|
1293
|
+
if (routeClone.children) {
|
|
1294
|
+
routeClone.children = enhanceManualRouteObjects(routeClone.children);
|
|
1295
|
+
}
|
|
1296
|
+
|
|
1297
|
+
return routeClone;
|
|
1298
|
+
});
|
|
1299
|
+
}
|
|
1300
|
+
|
|
1301
|
+
function createMemoryRouter(routes, opts) {
|
|
1302
|
+
return createRouter({
|
|
1303
|
+
basename: opts?.basename,
|
|
1304
|
+
history: createMemoryHistory({
|
|
1305
|
+
initialEntries: opts?.initialEntries,
|
|
1306
|
+
initialIndex: opts?.initialIndex
|
|
1307
|
+
}),
|
|
1308
|
+
hydrationData: opts?.hydrationData,
|
|
1309
|
+
routes: enhanceManualRouteObjects(routes)
|
|
1310
|
+
}).initialize();
|
|
1311
|
+
} ///////////////////////////////////////////////////////////////////////////////
|
|
1100
1312
|
|
|
1101
|
-
export {
|
|
1313
|
+
export { Await, MemoryRouter, Navigate, Outlet, Route, Router, RouterProvider, Routes, DataRouterContext as UNSAFE_DataRouterContext, DataRouterStateContext as UNSAFE_DataRouterStateContext, DataStaticRouterContext as UNSAFE_DataStaticRouterContext, LocationContext as UNSAFE_LocationContext, NavigationContext as UNSAFE_NavigationContext, RouteContext as UNSAFE_RouteContext, enhanceManualRouteObjects as UNSAFE_enhanceManualRouteObjects, createMemoryRouter, createRoutesFromChildren, createRoutesFromChildren as createRoutesFromElements, renderMatches, useActionData, useAsyncError, useAsyncValue, useHref, useInRouterContext, useLoaderData, useLocation, useMatch, useMatches, useNavigate, useNavigation, useNavigationType, useOutlet, useOutletContext, useParams, useResolvedPath, useRevalidator, useRouteError, useRouteLoaderData, useRoutes };
|
|
1102
1314
|
//# sourceMappingURL=react-router.development.js.map
|