UNPKG

30.4 kBJavaScriptView Raw
1/**
2 * react-router v8.0.0
3 *
4 * Copyright (c) Remix Software Inc.
5 *
6 * This source code is licensed under the MIT license found in the
7 * LICENSE.md file in the root directory of this source tree.
8 *
9 * @license MIT
10 */
11import { createMemoryHistory, invariant, parsePath, warning } from "./router/history.js";
12import { defaultMapRouteProperties, getResolveToMatches, getRoutePattern, resolveTo, stripBasename } from "./router/utils.js";
13import { createRouter } from "./router/router.js";
14import { AwaitContext, DataRouterContext, DataRouterStateContext, FetchersContext, LocationContext, NavigationContext, RouteContext, ViewTransitionContext, useIsRSCRouterContext } from "./context.js";
15import { _renderMatches, useActionData, useAsyncValue, useInRouterContext, useLoaderData, useLocation, useMatches, useNavigate, useOutlet, useParams, useRouteError, useRoutes, useRoutesImpl } from "./hooks.js";
16import { warnOnce } from "./server-runtime/warnings.js";
17import * as React$1 from "react";
18import { useOptimistic } from "react";
19//#region lib/components.tsx
20const hydrationRouteProperties = ["HydrateFallback", "hydrateFallbackElement"];
21/**
22* Create a new {@link DataRouter} that manages the application path using an
23* in-memory [`History`](https://developer.mozilla.org/en-US/docs/Web/API/History)
24* stack. Useful for non-browser environments without a DOM API.
25*
26* Data Routers should not be held in React state. You should create your router
27* once outside of the React tree and pass it to {@link RouterProvider | `<RouterProvider>`}.
28* You can use `patchRoutesOnNavigation` to add additional routes programmatically.
29*
30* @public
31* @category Data Routers
32* @mode data
33* @param routes Application routes
34* @param opts Options
35* @param {MemoryRouterOpts.basename} opts.basename n/a
36* @param {MemoryRouterOpts.dataStrategy} opts.dataStrategy n/a
37* @param {MemoryRouterOpts.future} opts.future n/a
38* @param {MemoryRouterOpts.getContext} opts.getContext n/a
39* @param {MemoryRouterOpts.hydrationData} opts.hydrationData n/a
40* @param {MemoryRouterOpts.initialEntries} opts.initialEntries n/a
41* @param {MemoryRouterOpts.initialIndex} opts.initialIndex n/a
42* @param {MemoryRouterOpts.instrumentations} opts.instrumentations n/a
43* @param {MemoryRouterOpts.patchRoutesOnNavigation} opts.patchRoutesOnNavigation n/a
44* @returns An initialized {@link DataRouter} to pass to {@link RouterProvider | `<RouterProvider>`}
45*/
46function createMemoryRouter(routes, opts) {
47 return createRouter({
48 basename: opts?.basename,
49 getContext: opts?.getContext,
50 future: opts?.future,
51 history: createMemoryHistory({
52 initialEntries: opts?.initialEntries,
53 initialIndex: opts?.initialIndex
54 }),
55 hydrationData: opts?.hydrationData,
56 routes,
57 mapRouteProperties: defaultMapRouteProperties,
58 hydrationRouteProperties,
59 dataStrategy: opts?.dataStrategy,
60 patchRoutesOnNavigation: opts?.patchRoutesOnNavigation,
61 instrumentations: opts?.instrumentations
62 }).initialize();
63}
64var Deferred = class {
65 status = "pending";
66 promise;
67 resolve;
68 reject;
69 constructor() {
70 this.promise = new Promise((resolve, reject) => {
71 this.resolve = (value) => {
72 if (this.status === "pending") {
73 this.status = "resolved";
74 resolve(value);
75 }
76 };
77 this.reject = (reason) => {
78 if (this.status === "pending") {
79 this.status = "rejected";
80 reject(reason);
81 }
82 };
83 });
84 }
85};
86/**
87* Render the UI for the given {@link DataRouter}. This component should
88* typically be at the top of an app's element tree. The router prop should
89* be a single router instance created outside of the React tree. Avoid
90* creating new routers during React renders/re-renders.
91*
92* ```tsx
93* import { createBrowserRouter } from "react-router";
94* import { RouterProvider } from "react-router/dom";
95* import { createRoot } from "react-dom/client";
96*
97* const router = createBrowserRouter(routes);
98* createRoot(document.getElementById("root")).render(
99* <RouterProvider router={router} />
100* );
101* ```
102*
103* <docs-info>Please note that this component is exported both from
104* `react-router` and `react-router/dom` with the only difference being that the
105* latter automatically wires up `react-dom`'s [`flushSync`](https://react.dev/reference/react-dom/flushSync)
106* implementation. You _almost always_ want to use the version from
107* `react-router/dom` unless you're running in a non-DOM environment.</docs-info>
108*
109*
110* @public
111* @category Data Routers
112* @mode data
113* @param props Props
114* @param {RouterProviderProps.flushSync} props.flushSync n/a
115* @param {RouterProviderProps.onError} props.onError n/a
116* @param {RouterProviderProps.router} props.router n/a
117* @param {RouterProviderProps.useTransitions} props.useTransitions n/a
118* @returns React element for the rendered router
119*/
120function RouterProvider({ router, flushSync: reactDomFlushSyncImpl, onError, useTransitions }) {
121 useTransitions = useIsRSCRouterContext() || useTransitions;
122 let [_state, setStateImpl] = React$1.useState(router.state);
123 let [state, setOptimisticState] = useOptimistic(_state);
124 let [pendingState, setPendingState] = React$1.useState();
125 let [vtContext, setVtContext] = React$1.useState({ isTransitioning: false });
126 let [renderDfd, setRenderDfd] = React$1.useState();
127 let [transition, setTransition] = React$1.useState();
128 let [interruption, setInterruption] = React$1.useState();
129 let fetcherData = React$1.useRef(/* @__PURE__ */ new Map());
130 let setState = React$1.useCallback((newState, { deletedFetchers, newErrors, flushSync, viewTransitionOpts }) => {
131 if (newErrors && onError) Object.values(newErrors).forEach((error) => onError(error, {
132 location: newState.location,
133 params: newState.matches[0]?.params ?? {},
134 pattern: getRoutePattern(newState.matches)
135 }));
136 newState.fetchers.forEach((fetcher, key) => {
137 if (fetcher.data !== void 0) fetcherData.current.set(key, fetcher.data);
138 });
139 deletedFetchers.forEach((key) => fetcherData.current.delete(key));
140 warnOnce(flushSync === false || reactDomFlushSyncImpl != null, "You provided the `flushSync` option to a router update, but you are not using the `<RouterProvider>` from `react-router/dom` so `ReactDOM.flushSync()` is unavailable. Please update your app to `import { RouterProvider } from \"react-router/dom\"` and ensure you have `react-dom` installed as a dependency to use the `flushSync` option.");
141 let isViewTransitionAvailable = router.window != null && router.window.document != null && typeof router.window.document.startViewTransition === "function";
142 warnOnce(viewTransitionOpts == null || isViewTransitionAvailable, "You provided the `viewTransition` option to a router update, but you do not appear to be running in a DOM environment as `window.startViewTransition` is not available.");
143 if (!viewTransitionOpts || !isViewTransitionAvailable) {
144 if (reactDomFlushSyncImpl && flushSync) reactDomFlushSyncImpl(() => setStateImpl(newState));
145 else if (useTransitions === false) setStateImpl(newState);
146 else React$1.startTransition(() => {
147 if (useTransitions === true) setOptimisticState((s) => getOptimisticRouterState(s, newState));
148 setStateImpl(newState);
149 });
150 return;
151 }
152 if (reactDomFlushSyncImpl && flushSync) {
153 reactDomFlushSyncImpl(() => {
154 if (transition) {
155 renderDfd?.resolve();
156 transition.skipTransition();
157 }
158 setVtContext({
159 isTransitioning: true,
160 flushSync: true,
161 currentLocation: viewTransitionOpts.currentLocation,
162 nextLocation: viewTransitionOpts.nextLocation
163 });
164 });
165 let t = router.window.document.startViewTransition(() => {
166 reactDomFlushSyncImpl(() => setStateImpl(newState));
167 });
168 t.finished.finally(() => {
169 reactDomFlushSyncImpl(() => {
170 setRenderDfd(void 0);
171 setTransition(void 0);
172 setPendingState(void 0);
173 setVtContext({ isTransitioning: false });
174 });
175 });
176 reactDomFlushSyncImpl(() => setTransition(t));
177 return;
178 }
179 if (transition) {
180 renderDfd?.resolve();
181 transition.skipTransition();
182 setInterruption({
183 state: newState,
184 currentLocation: viewTransitionOpts.currentLocation,
185 nextLocation: viewTransitionOpts.nextLocation
186 });
187 } else {
188 setPendingState(newState);
189 setVtContext({
190 isTransitioning: true,
191 flushSync: false,
192 currentLocation: viewTransitionOpts.currentLocation,
193 nextLocation: viewTransitionOpts.nextLocation
194 });
195 }
196 }, [
197 router.window,
198 reactDomFlushSyncImpl,
199 transition,
200 renderDfd,
201 useTransitions,
202 setOptimisticState,
203 onError
204 ]);
205 React$1.useLayoutEffect(() => router.subscribe(setState), [router, setState]);
206 React$1.useEffect(() => {
207 if (vtContext.isTransitioning && !vtContext.flushSync) setRenderDfd(new Deferred());
208 }, [vtContext]);
209 React$1.useEffect(() => {
210 if (renderDfd && pendingState && router.window) {
211 let newState = pendingState;
212 let renderPromise = renderDfd.promise;
213 let transition = router.window.document.startViewTransition(async () => {
214 if (useTransitions === false) setStateImpl(newState);
215 else React$1.startTransition(() => {
216 if (useTransitions === true) setOptimisticState((s) => getOptimisticRouterState(s, newState));
217 setStateImpl(newState);
218 });
219 await renderPromise;
220 });
221 transition.finished.finally(() => {
222 setRenderDfd(void 0);
223 setTransition(void 0);
224 setPendingState(void 0);
225 setVtContext({ isTransitioning: false });
226 });
227 setTransition(transition);
228 }
229 }, [
230 pendingState,
231 renderDfd,
232 router.window,
233 useTransitions,
234 setOptimisticState
235 ]);
236 React$1.useEffect(() => {
237 if (renderDfd && pendingState && state.location.key === pendingState.location.key) renderDfd.resolve();
238 }, [
239 renderDfd,
240 transition,
241 state.location,
242 pendingState
243 ]);
244 React$1.useEffect(() => {
245 if (!vtContext.isTransitioning && interruption) {
246 setPendingState(interruption.state);
247 setVtContext({
248 isTransitioning: true,
249 flushSync: false,
250 currentLocation: interruption.currentLocation,
251 nextLocation: interruption.nextLocation
252 });
253 setInterruption(void 0);
254 }
255 }, [vtContext.isTransitioning, interruption]);
256 let navigator = React$1.useMemo(() => {
257 return {
258 createHref: router.createHref,
259 encodeLocation: router.encodeLocation,
260 go: (n) => router.navigate(n),
261 push: (to, state, opts) => router.navigate(to, {
262 state,
263 preventScrollReset: opts?.preventScrollReset
264 }),
265 replace: (to, state, opts) => router.navigate(to, {
266 replace: true,
267 state,
268 preventScrollReset: opts?.preventScrollReset
269 })
270 };
271 }, [router]);
272 let basename = router.basename || "/";
273 let dataRouterContext = React$1.useMemo(() => ({
274 router,
275 navigator,
276 static: false,
277 basename,
278 onError
279 }), [
280 router,
281 navigator,
282 basename,
283 onError
284 ]);
285 return /* @__PURE__ */ React$1.createElement(React$1.Fragment, null, /* @__PURE__ */ React$1.createElement(DataRouterContext.Provider, { value: dataRouterContext }, /* @__PURE__ */ React$1.createElement(DataRouterStateContext.Provider, { value: state }, /* @__PURE__ */ React$1.createElement(FetchersContext.Provider, { value: fetcherData.current }, /* @__PURE__ */ React$1.createElement(ViewTransitionContext.Provider, { value: vtContext }, /* @__PURE__ */ React$1.createElement(Router, {
286 basename,
287 location: state.location,
288 navigationType: state.historyAction,
289 navigator,
290 useTransitions
291 }, /* @__PURE__ */ React$1.createElement(MemoizedDataRoutes, {
292 routes: router.routes,
293 manifest: router.manifest,
294 future: router.future,
295 state,
296 isStatic: false,
297 onError
298 })))))), null);
299}
300function getOptimisticRouterState(currentState, newState) {
301 return {
302 ...currentState,
303 navigation: newState.navigation.state !== "idle" ? newState.navigation : currentState.navigation,
304 revalidation: newState.revalidation !== "idle" ? newState.revalidation : currentState.revalidation,
305 actionData: newState.navigation.state !== "submitting" ? newState.actionData : currentState.actionData,
306 fetchers: newState.fetchers
307 };
308}
309const MemoizedDataRoutes = React$1.memo(DataRoutes);
310function DataRoutes({ routes, manifest, future, state, isStatic, onError }) {
311 return useRoutesImpl(routes, void 0, {
312 manifest,
313 state,
314 isStatic,
315 onError,
316 future
317 });
318}
319/**
320* A declarative {@link Router | `<Router>`} that stores all entries in memory.
321*
322* @public
323* @category Declarative Routers
324* @mode declarative
325* @param props Props
326* @param {MemoryRouterProps.basename} props.basename n/a
327* @param {MemoryRouterProps.children} props.children n/a
328* @param {MemoryRouterProps.initialEntries} props.initialEntries n/a
329* @param {MemoryRouterProps.initialIndex} props.initialIndex n/a
330* @param {MemoryRouterProps.useTransitions} props.useTransitions n/a
331* @returns A declarative in-memory {@link Router | `<Router>`} for client-side
332* routing.
333*/
334function MemoryRouter({ basename, children, initialEntries, initialIndex, useTransitions }) {
335 let historyRef = React$1.useRef(null);
336 if (historyRef.current == null) historyRef.current = createMemoryHistory({
337 initialEntries,
338 initialIndex,
339 v5Compat: true
340 });
341 let history = historyRef.current;
342 let [state, setStateImpl] = React$1.useState({
343 action: history.action,
344 location: history.location
345 });
346 let setState = React$1.useCallback((newState) => {
347 if (useTransitions === false) setStateImpl(newState);
348 else React$1.startTransition(() => setStateImpl(newState));
349 }, [useTransitions]);
350 React$1.useLayoutEffect(() => history.listen(setState), [history, setState]);
351 return /* @__PURE__ */ React$1.createElement(Router, {
352 basename,
353 children,
354 location: state.location,
355 navigationType: state.action,
356 navigator: history,
357 useTransitions
358 });
359}
360/**
361* A component-based version of {@link useNavigate} to use in a
362* [`React.Component` class](https://react.dev/reference/react/Component) where
363* hooks cannot be used.
364*
365* It's recommended to avoid using this component in favor of {@link useNavigate}.
366*
367* @example
368* <Navigate to="/tasks" />
369*
370* @public
371* @category Components
372* @param props Props
373* @param {NavigateProps.relative} props.relative n/a
374* @param {NavigateProps.replace} props.replace n/a
375* @param {NavigateProps.state} props.state n/a
376* @param {NavigateProps.to} props.to n/a
377* @returns {void}
378*
379*/
380function Navigate({ to, replace, state, relative }) {
381 invariant(useInRouterContext(), `<Navigate> may be used only in the context of a <Router> component.`);
382 let { static: isStatic } = React$1.useContext(NavigationContext);
383 warning(!isStatic, "<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.");
384 let { matches } = React$1.useContext(RouteContext);
385 let { pathname: locationPathname } = useLocation();
386 let navigate = useNavigate();
387 let path = resolveTo(to, getResolveToMatches(matches), locationPathname, relative === "path");
388 let jsonPath = JSON.stringify(path);
389 React$1.useEffect(() => {
390 navigate(JSON.parse(jsonPath), {
391 replace,
392 state,
393 relative
394 });
395 }, [
396 navigate,
397 jsonPath,
398 relative,
399 replace,
400 state
401 ]);
402 return null;
403}
404/**
405* Renders the matching child route of a parent route or nothing if no child
406* route matches.
407*
408* @example
409* import { Outlet } from "react-router";
410*
411* export default function SomeParent() {
412* return (
413* <div>
414* <h1>Parent Content</h1>
415* <Outlet />
416* </div>
417* );
418* }
419*
420* @public
421* @category Components
422* @param props Props
423* @param {OutletProps.context} props.context n/a
424* @returns React element for the rendered outlet or `null` if no child route matches.
425*/
426function Outlet(props) {
427 return useOutlet(props.context);
428}
429/**
430* Configures an element to render when a pattern matches the current location.
431* It must be rendered within a {@link Routes} element. Note that these routes
432* do not participate in data loading, actions, code splitting, or any other
433* route module features.
434*
435* @example
436* // Usually used in a declarative router
437* function App() {
438* return (
439* <BrowserRouter>
440* <Routes>
441* <Route index element={<StepOne />} />
442* <Route path="step-2" element={<StepTwo />} />
443* <Route path="step-3" element={<StepThree />} />
444* </Routes>
445* </BrowserRouter>
446* );
447* }
448*
449* // But can be used with a data router as well if you prefer the JSX notation
450* const routes = createRoutesFromElements(
451* <>
452* <Route index loader={step1Loader} Component={StepOne} />
453* <Route path="step-2" loader={step2Loader} Component={StepTwo} />
454* <Route path="step-3" loader={step3Loader} Component={StepThree} />
455* </>
456* );
457*
458* const router = createBrowserRouter(routes);
459*
460* function App() {
461* return <RouterProvider router={router} />;
462* }
463*
464* @public
465* @category Components
466* @param props Props
467* @param {PathRouteProps.action} props.action n/a
468* @param {PathRouteProps.caseSensitive} props.caseSensitive n/a
469* @param {PathRouteProps.Component} props.Component n/a
470* @param {PathRouteProps.children} props.children n/a
471* @param {PathRouteProps.element} props.element n/a
472* @param {PathRouteProps.ErrorBoundary} props.ErrorBoundary n/a
473* @param {PathRouteProps.errorElement} props.errorElement n/a
474* @param {PathRouteProps.handle} props.handle n/a
475* @param {PathRouteProps.HydrateFallback} props.HydrateFallback n/a
476* @param {PathRouteProps.hydrateFallbackElement} props.hydrateFallbackElement n/a
477* @param {PathRouteProps.id} props.id n/a
478* @param {PathRouteProps.index} props.index n/a
479* @param {PathRouteProps.lazy} props.lazy n/a
480* @param {PathRouteProps.loader} props.loader n/a
481* @param {PathRouteProps.path} props.path n/a
482* @param {PathRouteProps.shouldRevalidate} props.shouldRevalidate n/a
483* @returns {void}
484*/
485function Route(props) {
486 invariant(false, "A <Route> is only ever to be used as the child of <Routes> element, never rendered directly. Please wrap your <Route> in a <Routes>.");
487}
488/**
489* Provides location context for the rest of the app.
490*
491* Note: You usually won't render a `<Router>` directly. Instead, you'll render a
492* router that is more specific to your environment such as a {@link BrowserRouter}
493* in web browsers or a {@link ServerRouter} for server rendering.
494*
495* @public
496* @category Declarative Routers
497* @mode declarative
498* @param props Props
499* @param {RouterProps.basename} props.basename n/a
500* @param {RouterProps.children} props.children n/a
501* @param {RouterProps.location} props.location n/a
502* @param {RouterProps.navigationType} props.navigationType n/a
503* @param {RouterProps.navigator} props.navigator n/a
504* @param {RouterProps.static} props.static n/a
505* @param {RouterProps.useTransitions} props.useTransitions n/a
506* @returns React element for the rendered router or `null` if the location does
507* not match the {@link props.basename}
508*/
509function Router({ basename: basenameProp = "/", children = null, location: locationProp, navigationType = "POP", navigator, static: staticProp = false, useTransitions }) {
510 invariant(!useInRouterContext(), "You cannot render a <Router> inside another <Router>. You should never have more than one in your app.");
511 let basename = basenameProp.replace(/^\/*/, "/");
512 let navigationContext = React$1.useMemo(() => ({
513 basename,
514 navigator,
515 static: staticProp,
516 useTransitions,
517 future: {}
518 }), [
519 basename,
520 navigator,
521 staticProp,
522 useTransitions
523 ]);
524 if (typeof locationProp === "string") locationProp = parsePath(locationProp);
525 let { pathname = "/", search = "", hash = "", state = null, key = "default", mask } = locationProp;
526 let locationContext = React$1.useMemo(() => {
527 let trailingPathname = stripBasename(pathname, basename);
528 if (trailingPathname == null) return null;
529 return {
530 location: {
531 pathname: trailingPathname,
532 search,
533 hash,
534 state,
535 key,
536 mask
537 },
538 navigationType
539 };
540 }, [
541 basename,
542 pathname,
543 search,
544 hash,
545 state,
546 key,
547 navigationType,
548 mask
549 ]);
550 warning(locationContext != null, `<Router basename="${basename}"> is not able to match the URL "${pathname}${search}${hash}" because it does not start with the basename, so the <Router> won't render anything.`);
551 if (locationContext == null) return null;
552 return /* @__PURE__ */ React$1.createElement(NavigationContext.Provider, { value: navigationContext }, /* @__PURE__ */ React$1.createElement(LocationContext.Provider, {
553 children,
554 value: locationContext
555 }));
556}
557/**
558* Renders a branch of {@link Route | `<Route>`s} that best matches the current
559* location. Note that these routes do not participate in [data loading](../../start/framework/route-module#loader),
560* [`action`](../../start/framework/route-module#action), code splitting, or
561* any other [route module](../../start/framework/route-module) features.
562*
563* @example
564* import { Route, Routes } from "react-router";
565*
566* <Routes>
567* <Route index element={<StepOne />} />
568* <Route path="step-2" element={<StepTwo />} />
569* <Route path="step-3" element={<StepThree />} />
570* </Routes>
571*
572* @public
573* @category Components
574* @param props Props
575* @param {RoutesProps.children} props.children n/a
576* @param {RoutesProps.location} props.location n/a
577* @returns React element for the rendered routes or `null` if no route matches
578*/
579function Routes({ children, location }) {
580 return useRoutes(createRoutesFromChildren(children), location);
581}
582/**
583* Used to render promise values with automatic error handling.
584*
585* **Note:** `<Await>` expects to be rendered inside a [`<React.Suspense>`](https://react.dev/reference/react/Suspense)
586*
587* @example
588* import { Await, useLoaderData } from "react-router";
589*
590* export async function loader() {
591* // not awaited
592* const reviews = getReviews();
593* // awaited (blocks the transition)
594* const book = await fetch("/api/book").then((res) => res.json());
595* return { book, reviews };
596* }
597*
598* function Book() {
599* const { book, reviews } = useLoaderData();
600* return (
601* <div>
602* <h1>{book.title}</h1>
603* <p>{book.description}</p>
604* <React.Suspense fallback={<ReviewsSkeleton />}>
605* <Await
606* resolve={reviews}
607* errorElement={
608* <div>Could not load reviews 😬</div>
609* }
610* children={(resolvedReviews) => (
611* <Reviews items={resolvedReviews} />
612* )}
613* />
614* </React.Suspense>
615* </div>
616* );
617* }
618*
619* @public
620* @category Components
621* @mode framework
622* @mode data
623* @param props Props
624* @param {AwaitProps.children} props.children n/a
625* @param {AwaitProps.errorElement} props.errorElement n/a
626* @param {AwaitProps.resolve} props.resolve n/a
627* @returns React element for the rendered awaited value
628*/
629function Await({ children, errorElement, resolve }) {
630 let dataRouterContext = React$1.useContext(DataRouterContext);
631 let dataRouterStateContext = React$1.useContext(DataRouterStateContext);
632 let onError = React$1.useCallback((error, errorInfo) => {
633 if (dataRouterContext && dataRouterContext.onError && dataRouterStateContext) dataRouterContext.onError(error, {
634 location: dataRouterStateContext.location,
635 params: dataRouterStateContext.matches[0]?.params || {},
636 pattern: getRoutePattern(dataRouterStateContext.matches),
637 errorInfo
638 });
639 }, [dataRouterContext, dataRouterStateContext]);
640 return /* @__PURE__ */ React$1.createElement(AwaitErrorBoundary, {
641 resolve,
642 errorElement,
643 onError
644 }, /* @__PURE__ */ React$1.createElement(ResolveAwait, null, children));
645}
646var AwaitErrorBoundary = class extends React$1.Component {
647 constructor(props) {
648 super(props);
649 this.state = { error: null };
650 }
651 static getDerivedStateFromError(error) {
652 return { error };
653 }
654 componentDidCatch(error, errorInfo) {
655 if (this.props.onError) this.props.onError(error, errorInfo);
656 else console.error("<Await> caught the following error during render", error, errorInfo);
657 }
658 render() {
659 let { children, errorElement, resolve } = this.props;
660 let promise = null;
661 let status = 0;
662 if (!(resolve instanceof Promise)) {
663 status = 1;
664 promise = Promise.resolve();
665 Object.defineProperty(promise, "_tracked", { get: () => true });
666 Object.defineProperty(promise, "_data", { get: () => resolve });
667 } else if (this.state.error) {
668 status = 2;
669 let renderError = this.state.error;
670 promise = Promise.reject().catch(() => {});
671 Object.defineProperty(promise, "_tracked", { get: () => true });
672 Object.defineProperty(promise, "_error", { get: () => renderError });
673 } else if (resolve._tracked) {
674 promise = resolve;
675 status = "_error" in promise ? 2 : "_data" in promise ? 1 : 0;
676 } else {
677 status = 0;
678 Object.defineProperty(resolve, "_tracked", { get: () => true });
679 promise = resolve.then((data) => Object.defineProperty(resolve, "_data", { get: () => data }), (error) => {
680 this.props.onError?.(error);
681 Object.defineProperty(resolve, "_error", { get: () => error });
682 });
683 }
684 if (status === 2 && !errorElement) throw promise._error;
685 if (status === 2) return /* @__PURE__ */ React$1.createElement(AwaitContext.Provider, {
686 value: promise,
687 children: errorElement
688 });
689 if (status === 1) return /* @__PURE__ */ React$1.createElement(AwaitContext.Provider, {
690 value: promise,
691 children
692 });
693 throw promise;
694 }
695};
696function ResolveAwait({ children }) {
697 let data = useAsyncValue();
698 let toRender = typeof children === "function" ? children(data) : children;
699 return /* @__PURE__ */ React$1.createElement(React$1.Fragment, null, toRender);
700}
701/**
702* Creates a route config from a React "children" object, which is usually
703* either a `<Route>` element or an array of them. Used internally by
704* `<Routes>` to create a route config from its children.
705*
706* @category Utils
707* @mode data
708* @param children The React children to convert into a route config
709* @param parentPath The path of the parent route, used to generate unique IDs.
710* @returns An array of {@link RouteObject}s that can be used with a {@link DataRouter}
711*/
712function createRoutesFromChildren(children, parentPath = []) {
713 let routes = [];
714 React$1.Children.forEach(children, (element, index) => {
715 if (!React$1.isValidElement(element)) return;
716 let treePath = [...parentPath, index];
717 if (element.type === React$1.Fragment) {
718 routes.push.apply(routes, createRoutesFromChildren(element.props.children, treePath));
719 return;
720 }
721 invariant(element.type === Route, `[${typeof element.type === "string" ? element.type : element.type.name}] is not a <Route> component. All component children of <Routes> must be a <Route> or <React.Fragment>`);
722 let props = element.props;
723 invariant(!props.index || !props.children, "An index route cannot have child routes.");
724 let route = {
725 id: props.id || treePath.join("-"),
726 caseSensitive: props.caseSensitive,
727 element: props.element,
728 Component: props.Component,
729 index: props.index,
730 path: props.path,
731 middleware: props.middleware,
732 loader: props.loader,
733 action: props.action,
734 hydrateFallbackElement: props.hydrateFallbackElement,
735 HydrateFallback: props.HydrateFallback,
736 errorElement: props.errorElement,
737 ErrorBoundary: props.ErrorBoundary,
738 shouldRevalidate: props.shouldRevalidate,
739 handle: props.handle,
740 lazy: props.lazy
741 };
742 if (props.children) route.children = createRoutesFromChildren(props.children, treePath);
743 routes.push(route);
744 });
745 return routes;
746}
747/**
748* Create route objects from JSX elements instead of arrays of objects.
749*
750* @example
751* const routes = createRoutesFromElements(
752* <>
753* <Route index loader={step1Loader} Component={StepOne} />
754* <Route path="step-2" loader={step2Loader} Component={StepTwo} />
755* <Route path="step-3" loader={step3Loader} Component={StepThree} />
756* </>
757* );
758*
759* const router = createBrowserRouter(routes);
760*
761* function App() {
762* return <RouterProvider router={router} />;
763* }
764*
765* @name createRoutesFromElements
766* @public
767* @category Utils
768* @mode data
769* @param children The React children to convert into a route config
770* @param parentPath The path of the parent route, used to generate unique IDs.
771* This is used for internal recursion and is not intended to be used by the
772* application developer.
773* @returns An array of {@link RouteObject}s that can be used with a {@link DataRouter}
774*/
775const createRoutesFromElements = createRoutesFromChildren;
776/**
777* Renders the result of {@link matchRoutes} into a React element.
778*
779* @public
780* @category Utils
781* @param matches The array of {@link RouteMatch | route matches} to render
782* @returns A React element that renders the matched routes or `null` if no matches
783*/
784function renderMatches(matches) {
785 return _renderMatches(matches);
786}
787function useRouteComponentProps() {
788 return {
789 params: useParams(),
790 loaderData: useLoaderData(),
791 actionData: useActionData(),
792 matches: useMatches()
793 };
794}
795function WithComponentProps({ children }) {
796 const props = useRouteComponentProps();
797 return React$1.cloneElement(children, props);
798}
799function withComponentProps(Component) {
800 return function WithComponentProps() {
801 const props = useRouteComponentProps();
802 return React$1.createElement(Component, props);
803 };
804}
805function useHydrateFallbackProps() {
806 return {
807 params: useParams(),
808 loaderData: useLoaderData(),
809 actionData: useActionData()
810 };
811}
812function WithHydrateFallbackProps({ children }) {
813 const props = useHydrateFallbackProps();
814 return React$1.cloneElement(children, props);
815}
816function withHydrateFallbackProps(HydrateFallback) {
817 return function WithHydrateFallbackProps() {
818 const props = useHydrateFallbackProps();
819 return React$1.createElement(HydrateFallback, props);
820 };
821}
822function useErrorBoundaryProps() {
823 return {
824 params: useParams(),
825 loaderData: useLoaderData(),
826 actionData: useActionData(),
827 error: useRouteError()
828 };
829}
830function WithErrorBoundaryProps({ children }) {
831 const props = useErrorBoundaryProps();
832 return React$1.cloneElement(children, props);
833}
834function withErrorBoundaryProps(ErrorBoundary) {
835 return function WithErrorBoundaryProps() {
836 const props = useErrorBoundaryProps();
837 return React$1.createElement(ErrorBoundary, props);
838 };
839}
840//#endregion
841export { Await, DataRoutes, MemoryRouter, Navigate, Outlet, Route, Router, RouterProvider, Routes, WithComponentProps, WithErrorBoundaryProps, WithHydrateFallbackProps, createMemoryRouter, createRoutesFromChildren, createRoutesFromElements, hydrationRouteProperties, renderMatches, withComponentProps, withErrorBoundaryProps, withHydrateFallbackProps };