UNPKG

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