/** * React Router v6.26.2 * * Copyright (c) Remix Software Inc. * * This source code is licensed under the MIT license found in the * LICENSE.md file in the root directory of this source tree. * * @license MIT */ import * as React from 'react'; import { UNSAFE_invariant, joinPaths, matchPath, UNSAFE_decodePath, UNSAFE_getResolveToMatches, UNSAFE_warning, resolveTo, parsePath, matchRoutes, Action, UNSAFE_convertRouteMatchToUiMatch, stripBasename, IDLE_BLOCKER, isRouteErrorResponse, createMemoryHistory, AbortedDeferredError, createRouter } from '@remix-run/router'; export { AbortedDeferredError, Action as NavigationType, createPath, defer, generatePath, isRouteErrorResponse, json, matchPath, matchRoutes, parsePath, redirect, redirectDocument, replace, resolvePath } from '@remix-run/router'; function _extends() { _extends = Object.assign ? Object.assign.bind() : function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); } // Create react-specific types from the agnostic types in @remix-run/router to // export from react-router const DataRouterContext = /*#__PURE__*/React.createContext(null); if (process.env.NODE_ENV !== "production") { DataRouterContext.displayName = "DataRouter"; } const DataRouterStateContext = /*#__PURE__*/React.createContext(null); if (process.env.NODE_ENV !== "production") { DataRouterStateContext.displayName = "DataRouterState"; } const AwaitContext = /*#__PURE__*/React.createContext(null); if (process.env.NODE_ENV !== "production") { AwaitContext.displayName = "Await"; } /** * A Navigator is a "location changer"; it's how you get to different locations. * * Every history instance conforms to the Navigator interface, but the * distinction is useful primarily when it comes to the low-level `` API * where both the location and a navigator must be provided separately in order * to avoid "tearing" that may occur in a suspense-enabled app if the action * and/or location were to be read directly from the history instance. */ const NavigationContext = /*#__PURE__*/React.createContext(null); if (process.env.NODE_ENV !== "production") { NavigationContext.displayName = "Navigation"; } const LocationContext = /*#__PURE__*/React.createContext(null); if (process.env.NODE_ENV !== "production") { LocationContext.displayName = "Location"; } const RouteContext = /*#__PURE__*/React.createContext({ outlet: null, matches: [], isDataRoute: false }); if (process.env.NODE_ENV !== "production") { RouteContext.displayName = "Route"; } const RouteErrorContext = /*#__PURE__*/React.createContext(null); if (process.env.NODE_ENV !== "production") { RouteErrorContext.displayName = "RouteError"; } /** * Returns the full href for the given "to" value. This is useful for building * custom links that are also accessible and preserve right-click behavior. * * @see https://reactrouter.com/hooks/use-href */ function useHref(to, _temp) { let { relative } = _temp === void 0 ? {} : _temp; !useInRouterContext() ? process.env.NODE_ENV !== "production" ? UNSAFE_invariant(false, // TODO: This error is probably because they somehow have 2 versions of the // router loaded. We can help them understand how to avoid that. "useHref() may be used only in the context of a component.") : UNSAFE_invariant(false) : void 0; let { basename, navigator } = React.useContext(NavigationContext); let { hash, pathname, search } = useResolvedPath(to, { relative }); let joinedPathname = pathname; // If we're operating within a basename, prepend it to the pathname prior // to creating the href. If this is a root navigation, then just use the raw // basename which allows the basename to have full control over the presence // of a trailing slash on root links if (basename !== "/") { joinedPathname = pathname === "/" ? basename : joinPaths([basename, pathname]); } return navigator.createHref({ pathname: joinedPathname, search, hash }); } /** * Returns true if this component is a descendant of a ``. * * @see https://reactrouter.com/hooks/use-in-router-context */ function useInRouterContext() { return React.useContext(LocationContext) != null; } /** * Returns the current location object, which represents the current URL in web * browsers. * * Note: If you're using this it may mean you're doing some of your own * "routing" in your app, and we'd like to know what your use case is. We may * be able to provide something higher-level to better suit your needs. * * @see https://reactrouter.com/hooks/use-location */ function useLocation() { !useInRouterContext() ? process.env.NODE_ENV !== "production" ? UNSAFE_invariant(false, // TODO: This error is probably because they somehow have 2 versions of the // router loaded. We can help them understand how to avoid that. "useLocation() may be used only in the context of a component.") : UNSAFE_invariant(false) : void 0; return React.useContext(LocationContext).location; } /** * Returns the current navigation action which describes how the router came to * the current location, either by a pop, push, or replace on the history stack. * * @see https://reactrouter.com/hooks/use-navigation-type */ function useNavigationType() { return React.useContext(LocationContext).navigationType; } /** * Returns a PathMatch object if the given pattern matches the current URL. * This is useful for components that need to know "active" state, e.g. * ``. * * @see https://reactrouter.com/hooks/use-match */ function useMatch(pattern) { !useInRouterContext() ? process.env.NODE_ENV !== "production" ? UNSAFE_invariant(false, // TODO: This error is probably because they somehow have 2 versions of the // router loaded. We can help them understand how to avoid that. "useMatch() may be used only in the context of a component.") : UNSAFE_invariant(false) : void 0; let { pathname } = useLocation(); return React.useMemo(() => matchPath(pattern, UNSAFE_decodePath(pathname)), [pathname, pattern]); } /** * The interface for the navigate() function returned from useNavigate(). */ const navigateEffectWarning = "You should call navigate() in a React.useEffect(), not when " + "your component is first rendered."; // Mute warnings for calls to useNavigate in SSR environments function useIsomorphicLayoutEffect(cb) { let isStatic = React.useContext(NavigationContext).static; if (!isStatic) { // We should be able to get rid of this once react 18.3 is released // See: https://github.com/facebook/react/pull/26395 // eslint-disable-next-line react-hooks/rules-of-hooks React.useLayoutEffect(cb); } } /** * Returns an imperative method for changing the location. Used by ``s, but * may also be used by other elements to change the location. * * @see https://reactrouter.com/hooks/use-navigate */ function useNavigate() { let { isDataRoute } = React.useContext(RouteContext); // Conditional usage is OK here because the usage of a data router is static // eslint-disable-next-line react-hooks/rules-of-hooks return isDataRoute ? useNavigateStable() : useNavigateUnstable(); } function useNavigateUnstable() { !useInRouterContext() ? process.env.NODE_ENV !== "production" ? UNSAFE_invariant(false, // TODO: This error is probably because they somehow have 2 versions of the // router loaded. We can help them understand how to avoid that. "useNavigate() may be used only in the context of a component.") : UNSAFE_invariant(false) : void 0; let dataRouterContext = React.useContext(DataRouterContext); let { basename, future, navigator } = React.useContext(NavigationContext); let { matches } = React.useContext(RouteContext); let { pathname: locationPathname } = useLocation(); let routePathnamesJson = JSON.stringify(UNSAFE_getResolveToMatches(matches, future.v7_relativeSplatPath)); let activeRef = React.useRef(false); useIsomorphicLayoutEffect(() => { activeRef.current = true; }); let navigate = React.useCallback(function (to, options) { if (options === void 0) { options = {}; } process.env.NODE_ENV !== "production" ? UNSAFE_warning(activeRef.current, navigateEffectWarning) : void 0; // Short circuit here since if this happens on first render the navigate // is useless because we haven't wired up our history listener yet if (!activeRef.current) return; if (typeof to === "number") { navigator.go(to); return; } let path = resolveTo(to, JSON.parse(routePathnamesJson), locationPathname, options.relative === "path"); // If we're operating within a basename, prepend it to the pathname prior // to handing off to history (but only if we're not in a data router, // otherwise it'll prepend the basename inside of the router). // If this is a root navigation, then we navigate to the raw basename // which allows the basename to have full control over the presence of a // trailing slash on root links if (dataRouterContext == null && basename !== "/") { path.pathname = path.pathname === "/" ? basename : joinPaths([basename, path.pathname]); } (!!options.replace ? navigator.replace : navigator.push)(path, options.state, options); }, [basename, navigator, routePathnamesJson, locationPathname, dataRouterContext]); return navigate; } const OutletContext = /*#__PURE__*/React.createContext(null); /** * Returns the context (if provided) for the child route at this level of the route * hierarchy. * @see https://reactrouter.com/hooks/use-outlet-context */ function useOutletContext() { return React.useContext(OutletContext); } /** * Returns the element for the child route at this level of the route * hierarchy. Used internally by `` to render child routes. * * @see https://reactrouter.com/hooks/use-outlet */ function useOutlet(context) { let outlet = React.useContext(RouteContext).outlet; if (outlet) { return /*#__PURE__*/React.createElement(OutletContext.Provider, { value: context }, outlet); } return outlet; } /** * Returns an object of key/value pairs of the dynamic params from the current * URL that were matched by the route path. * * @see https://reactrouter.com/hooks/use-params */ function useParams() { let { matches } = React.useContext(RouteContext); let routeMatch = matches[matches.length - 1]; return routeMatch ? routeMatch.params : {}; } /** * Resolves the pathname of the given `to` value against the current location. * * @see https://reactrouter.com/hooks/use-resolved-path */ function useResolvedPath(to, _temp2) { let { relative } = _temp2 === void 0 ? {} : _temp2; let { future } = React.useContext(NavigationContext); let { matches } = React.useContext(RouteContext); let { pathname: locationPathname } = useLocation(); let routePathnamesJson = JSON.stringify(UNSAFE_getResolveToMatches(matches, future.v7_relativeSplatPath)); return React.useMemo(() => resolveTo(to, JSON.parse(routePathnamesJson), locationPathname, relative === "path"), [to, routePathnamesJson, locationPathname, relative]); } /** * Returns the element of the route that matched the current location, prepared * with the correct context to render the remainder of the route tree. Route * elements in the tree must render an `` to render their child route's * element. * * @see https://reactrouter.com/hooks/use-routes */ function useRoutes(routes, locationArg) { return useRoutesImpl(routes, locationArg); } // Internal implementation with accept optional param for RouterProvider usage function useRoutesImpl(routes, locationArg, dataRouterState, future) { !useInRouterContext() ? process.env.NODE_ENV !== "production" ? UNSAFE_invariant(false, // TODO: This error is probably because they somehow have 2 versions of the // router loaded. We can help them understand how to avoid that. "useRoutes() may be used only in the context of a component.") : UNSAFE_invariant(false) : void 0; let { navigator } = React.useContext(NavigationContext); let { matches: parentMatches } = React.useContext(RouteContext); let routeMatch = parentMatches[parentMatches.length - 1]; let parentParams = routeMatch ? routeMatch.params : {}; let parentPathname = routeMatch ? routeMatch.pathname : "/"; let parentPathnameBase = routeMatch ? routeMatch.pathnameBase : "/"; let parentRoute = routeMatch && routeMatch.route; if (process.env.NODE_ENV !== "production") { // You won't get a warning about 2 different under a // without a trailing *, but this is a best-effort warning anyway since we // cannot even give the warning unless they land at the parent route. // // Example: // // // {/* This route path MUST end with /* because otherwise // it will never match /blog/post/123 */} // } /> // } /> // // // function Blog() { // return ( // // } /> // // ); // } let parentPath = parentRoute && parentRoute.path || ""; warningOnce(parentPathname, !parentRoute || parentPath.endsWith("*"), "You rendered descendant (or called `useRoutes()`) at " + ("\"" + parentPathname + "\" (under ) but the ") + "parent route path has no trailing \"*\". This means if you navigate " + "deeper, the parent won't match anymore and therefore the child " + "routes will never render.\n\n" + ("Please change the parent to .")); } let locationFromContext = useLocation(); let location; if (locationArg) { var _parsedLocationArg$pa; let parsedLocationArg = typeof locationArg === "string" ? parsePath(locationArg) : locationArg; !(parentPathnameBase === "/" || ((_parsedLocationArg$pa = parsedLocationArg.pathname) == null ? void 0 : _parsedLocationArg$pa.startsWith(parentPathnameBase))) ? process.env.NODE_ENV !== "production" ? UNSAFE_invariant(false, "When overriding the location using `` or `useRoutes(routes, location)`, " + "the location pathname must begin with the portion of the URL pathname that was " + ("matched by all parent routes. The current pathname base is \"" + parentPathnameBase + "\" ") + ("but pathname \"" + parsedLocationArg.pathname + "\" was given in the `location` prop.")) : UNSAFE_invariant(false) : void 0; location = parsedLocationArg; } else { location = locationFromContext; } let pathname = location.pathname || "/"; let remainingPathname = pathname; if (parentPathnameBase !== "/") { // Determine the remaining pathname by removing the # of URL segments the // parentPathnameBase has, instead of removing based on character count. // This is because we can't guarantee that incoming/outgoing encodings/ // decodings will match exactly. // We decode paths before matching on a per-segment basis with // decodeURIComponent(), but we re-encode pathnames via `new URL()` so they // match what `window.location.pathname` would reflect. Those don't 100% // align when it comes to encoded URI characters such as % and &. // // So we may end up with: // pathname: "/descendant/a%25b/match" // parentPathnameBase: "/descendant/a%b" // // And the direct substring removal approach won't work :/ let parentSegments = parentPathnameBase.replace(/^\//, "").split("/"); let segments = pathname.replace(/^\//, "").split("/"); remainingPathname = "/" + segments.slice(parentSegments.length).join("/"); } let matches = matchRoutes(routes, { pathname: remainingPathname }); if (process.env.NODE_ENV !== "production") { process.env.NODE_ENV !== "production" ? UNSAFE_warning(parentRoute || matches != null, "No routes matched location \"" + location.pathname + location.search + location.hash + "\" ") : void 0; process.env.NODE_ENV !== "production" ? UNSAFE_warning(matches == null || matches[matches.length - 1].route.element !== undefined || matches[matches.length - 1].route.Component !== undefined || matches[matches.length - 1].route.lazy !== undefined, "Matched leaf route at location \"" + location.pathname + location.search + location.hash + "\" " + "does not have an element or Component. This means it will render an with a " + "null value by default resulting in an \"empty\" page.") : void 0; } let renderedMatches = _renderMatches(matches && matches.map(match => Object.assign({}, match, { params: Object.assign({}, parentParams, match.params), pathname: joinPaths([parentPathnameBase, // Re-encode pathnames that were decoded inside matchRoutes navigator.encodeLocation ? navigator.encodeLocation(match.pathname).pathname : match.pathname]), pathnameBase: match.pathnameBase === "/" ? parentPathnameBase : joinPaths([parentPathnameBase, // Re-encode pathnames that were decoded inside matchRoutes navigator.encodeLocation ? navigator.encodeLocation(match.pathnameBase).pathname : match.pathnameBase]) })), parentMatches, dataRouterState, future); // When a user passes in a `locationArg`, the associated routes need to // be wrapped in a new `LocationContext.Provider` in order for `useLocation` // to use the scoped location instead of the global location. if (locationArg && renderedMatches) { return /*#__PURE__*/React.createElement(LocationContext.Provider, { value: { location: _extends({ pathname: "/", search: "", hash: "", state: null, key: "default" }, location), navigationType: Action.Pop } }, renderedMatches); } return renderedMatches; } function DefaultErrorComponent() { let error = useRouteError(); let message = isRouteErrorResponse(error) ? error.status + " " + error.statusText : error instanceof Error ? error.message : JSON.stringify(error); let stack = error instanceof Error ? error.stack : null; let lightgrey = "rgba(200,200,200, 0.5)"; let preStyles = { padding: "0.5rem", backgroundColor: lightgrey }; let codeStyles = { padding: "2px 4px", backgroundColor: lightgrey }; let devInfo = null; if (process.env.NODE_ENV !== "production") { console.error("Error handled by React Router default ErrorBoundary:", error); devInfo = /*#__PURE__*/React.createElement(React.Fragment, 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 ", /*#__PURE__*/React.createElement("code", { style: codeStyles }, "ErrorBoundary"), " or", " ", /*#__PURE__*/React.createElement("code", { style: codeStyles }, "errorElement"), " prop on your route.")); } return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement("h2", null, "Unexpected Application Error!"), /*#__PURE__*/React.createElement("h3", { style: { fontStyle: "italic" } }, message), stack ? /*#__PURE__*/React.createElement("pre", { style: preStyles }, stack) : null, devInfo); } const defaultErrorElement = /*#__PURE__*/React.createElement(DefaultErrorComponent, null); class RenderErrorBoundary extends React.Component { constructor(props) { super(props); this.state = { location: props.location, revalidation: props.revalidation, error: props.error }; } static getDerivedStateFromError(error) { return { error: error }; } static getDerivedStateFromProps(props, state) { // When we get into an error state, the user will likely click "back" to the // previous page that didn't have an error. Because this wraps the entire // application, that will have no effect--the error page continues to display. // This gives us a mechanism to recover from the error when the location changes. // // Whether we're in an error state or not, we update the location in state // so that when we are in an error state, it gets reset when a new location // comes in and the user recovers from the error. if (state.location !== props.location || state.revalidation !== "idle" && props.revalidation === "idle") { return { error: props.error, location: props.location, revalidation: props.revalidation }; } // If we're not changing locations, preserve the location but still surface // any new errors that may come through. We retain the existing error, we do // this because the error provided from the app state may be cleared without // the location changing. return { error: props.error !== undefined ? props.error : state.error, location: state.location, revalidation: props.revalidation || state.revalidation }; } componentDidCatch(error, errorInfo) { console.error("React Router caught the following error during render", error, errorInfo); } render() { return this.state.error !== undefined ? /*#__PURE__*/React.createElement(RouteContext.Provider, { value: this.props.routeContext }, /*#__PURE__*/React.createElement(RouteErrorContext.Provider, { value: this.state.error, children: this.props.component })) : this.props.children; } } function RenderedRoute(_ref) { let { routeContext, match, children } = _ref; let dataRouterContext = React.useContext(DataRouterContext); // Track how deep we got in our render pass to emulate SSR componentDidCatch // in a DataStaticRouter if (dataRouterContext && dataRouterContext.static && dataRouterContext.staticContext && (match.route.errorElement || match.route.ErrorBoundary)) { dataRouterContext.staticContext._deepestRenderedBoundaryId = match.route.id; } return /*#__PURE__*/React.createElement(RouteContext.Provider, { value: routeContext }, children); } function _renderMatches(matches, parentMatches, dataRouterState, future) { var _dataRouterState; if (parentMatches === void 0) { parentMatches = []; } if (dataRouterState === void 0) { dataRouterState = null; } if (future === void 0) { future = null; } if (matches == null) { var _future; if (!dataRouterState) { return null; } if (dataRouterState.errors) { // Don't bail if we have data router errors so we can render them in the // boundary. Use the pre-matched (or shimmed) matches matches = dataRouterState.matches; } else if ((_future = future) != null && _future.v7_partialHydration && parentMatches.length === 0 && !dataRouterState.initialized && dataRouterState.matches.length > 0) { // Don't bail if we're initializing with partial hydration and we have // router matches. That means we're actively running `patchRoutesOnNavigation` // so we should render down the partial matches to the appropriate // `HydrateFallback`. We only do this if `parentMatches` is empty so it // only impacts the root matches for `RouterProvider` and no descendant // `` matches = dataRouterState.matches; } else { return null; } } let renderedMatches = matches; // If we have data errors, trim matches to the highest error boundary let errors = (_dataRouterState = dataRouterState) == null ? void 0 : _dataRouterState.errors; if (errors != null) { let errorIndex = renderedMatches.findIndex(m => m.route.id && (errors == null ? void 0 : errors[m.route.id]) !== undefined); !(errorIndex >= 0) ? process.env.NODE_ENV !== "production" ? UNSAFE_invariant(false, "Could not find a matching route for errors on route IDs: " + Object.keys(errors).join(",")) : UNSAFE_invariant(false) : void 0; renderedMatches = renderedMatches.slice(0, Math.min(renderedMatches.length, errorIndex + 1)); } // If we're in a partial hydration mode, detect if we need to render down to // a given HydrateFallback while we load the rest of the hydration data let renderFallback = false; let fallbackIndex = -1; if (dataRouterState && future && future.v7_partialHydration) { for (let i = 0; i < renderedMatches.length; i++) { let match = renderedMatches[i]; // Track the deepest fallback up until the first route without data if (match.route.HydrateFallback || match.route.hydrateFallbackElement) { fallbackIndex = i; } if (match.route.id) { let { loaderData, errors } = dataRouterState; let needsToRunLoader = match.route.loader && loaderData[match.route.id] === undefined && (!errors || errors[match.route.id] === undefined); if (match.route.lazy || needsToRunLoader) { // We found the first route that's not ready to render (waiting on // lazy, or has a loader that hasn't run yet). Flag that we need to // render a fallback and render up until the appropriate fallback renderFallback = true; if (fallbackIndex >= 0) { renderedMatches = renderedMatches.slice(0, fallbackIndex + 1); } else { renderedMatches = [renderedMatches[0]]; } break; } } } } return renderedMatches.reduceRight((outlet, match, index) => { // Only data routers handle errors/fallbacks let error; let shouldRenderHydrateFallback = false; let errorElement = null; let hydrateFallbackElement = null; if (dataRouterState) { error = errors && match.route.id ? errors[match.route.id] : undefined; errorElement = match.route.errorElement || defaultErrorElement; if (renderFallback) { if (fallbackIndex < 0 && index === 0) { warningOnce("route-fallback", false, "No `HydrateFallback` element provided to render during initial hydration"); shouldRenderHydrateFallback = true; hydrateFallbackElement = null; } else if (fallbackIndex === index) { shouldRenderHydrateFallback = true; hydrateFallbackElement = match.route.hydrateFallbackElement || null; } } } let matches = parentMatches.concat(renderedMatches.slice(0, index + 1)); let getChildren = () => { let children; if (error) { children = errorElement; } else if (shouldRenderHydrateFallback) { children = hydrateFallbackElement; } else if (match.route.Component) { // Note: This is a de-optimized path since React won't re-use the // ReactElement since it's identity changes with each new // React.createElement call. We keep this so folks can use // `` in `` but generally `Component` // usage is only advised in `RouterProvider` when we can convert it to // `element` ahead of time. children = /*#__PURE__*/React.createElement(match.route.Component, null); } else if (match.route.element) { children = match.route.element; } else { children = outlet; } return /*#__PURE__*/React.createElement(RenderedRoute, { match: match, routeContext: { outlet, matches, isDataRoute: dataRouterState != null }, children: children }); }; // Only wrap in an error boundary within data router usages when we have an // ErrorBoundary/errorElement on this route. Otherwise let it bubble up to // an ancestor ErrorBoundary/errorElement return dataRouterState && (match.route.ErrorBoundary || match.route.errorElement || index === 0) ? /*#__PURE__*/React.createElement(RenderErrorBoundary, { location: dataRouterState.location, revalidation: dataRouterState.revalidation, component: errorElement, error: error, children: getChildren(), routeContext: { outlet: null, matches, isDataRoute: true } }) : getChildren(); }, null); } var DataRouterHook = /*#__PURE__*/function (DataRouterHook) { DataRouterHook["UseBlocker"] = "useBlocker"; DataRouterHook["UseRevalidator"] = "useRevalidator"; DataRouterHook["UseNavigateStable"] = "useNavigate"; return DataRouterHook; }(DataRouterHook || {}); var DataRouterStateHook = /*#__PURE__*/function (DataRouterStateHook) { DataRouterStateHook["UseBlocker"] = "useBlocker"; DataRouterStateHook["UseLoaderData"] = "useLoaderData"; DataRouterStateHook["UseActionData"] = "useActionData"; DataRouterStateHook["UseRouteError"] = "useRouteError"; DataRouterStateHook["UseNavigation"] = "useNavigation"; DataRouterStateHook["UseRouteLoaderData"] = "useRouteLoaderData"; DataRouterStateHook["UseMatches"] = "useMatches"; DataRouterStateHook["UseRevalidator"] = "useRevalidator"; DataRouterStateHook["UseNavigateStable"] = "useNavigate"; DataRouterStateHook["UseRouteId"] = "useRouteId"; return DataRouterStateHook; }(DataRouterStateHook || {}); function getDataRouterConsoleError(hookName) { return hookName + " must be used within a data router. See https://reactrouter.com/routers/picking-a-router."; } function useDataRouterContext(hookName) { let ctx = React.useContext(DataRouterContext); !ctx ? process.env.NODE_ENV !== "production" ? UNSAFE_invariant(false, getDataRouterConsoleError(hookName)) : UNSAFE_invariant(false) : void 0; return ctx; } function useDataRouterState(hookName) { let state = React.useContext(DataRouterStateContext); !state ? process.env.NODE_ENV !== "production" ? UNSAFE_invariant(false, getDataRouterConsoleError(hookName)) : UNSAFE_invariant(false) : void 0; return state; } function useRouteContext(hookName) { let route = React.useContext(RouteContext); !route ? process.env.NODE_ENV !== "production" ? UNSAFE_invariant(false, getDataRouterConsoleError(hookName)) : UNSAFE_invariant(false) : void 0; return route; } // Internal version with hookName-aware debugging function useCurrentRouteId(hookName) { let route = useRouteContext(hookName); let thisRoute = route.matches[route.matches.length - 1]; !thisRoute.route.id ? process.env.NODE_ENV !== "production" ? UNSAFE_invariant(false, hookName + " can only be used on routes that contain a unique \"id\"") : UNSAFE_invariant(false) : void 0; return thisRoute.route.id; } /** * Returns the ID for the nearest contextual route */ function useRouteId() { return useCurrentRouteId(DataRouterStateHook.UseRouteId); } /** * Returns the current navigation, defaulting to an "idle" navigation when * no navigation is in progress */ function useNavigation() { let state = useDataRouterState(DataRouterStateHook.UseNavigation); return state.navigation; } /** * Returns a revalidate function for manually triggering revalidation, as well * as the current state of any manual revalidations */ function useRevalidator() { let dataRouterContext = useDataRouterContext(DataRouterHook.UseRevalidator); let state = useDataRouterState(DataRouterStateHook.UseRevalidator); return React.useMemo(() => ({ revalidate: dataRouterContext.router.revalidate, state: state.revalidation }), [dataRouterContext.router.revalidate, state.revalidation]); } /** * Returns the active route matches, useful for accessing loaderData for * parent/child routes or the route "handle" property */ function useMatches() { let { matches, loaderData } = useDataRouterState(DataRouterStateHook.UseMatches); return React.useMemo(() => matches.map(m => UNSAFE_convertRouteMatchToUiMatch(m, loaderData)), [matches, loaderData]); } /** * Returns the loader data for the nearest ancestor Route loader */ function useLoaderData() { let state = useDataRouterState(DataRouterStateHook.UseLoaderData); let routeId = useCurrentRouteId(DataRouterStateHook.UseLoaderData); if (state.errors && state.errors[routeId] != null) { console.error("You cannot `useLoaderData` in an errorElement (routeId: " + routeId + ")"); return undefined; } return state.loaderData[routeId]; } /** * Returns the loaderData for the given routeId */ function useRouteLoaderData(routeId) { let state = useDataRouterState(DataRouterStateHook.UseRouteLoaderData); return state.loaderData[routeId]; } /** * Returns the action data for the nearest ancestor Route action */ function useActionData() { let state = useDataRouterState(DataRouterStateHook.UseActionData); let routeId = useCurrentRouteId(DataRouterStateHook.UseLoaderData); return state.actionData ? state.actionData[routeId] : undefined; } /** * Returns the nearest ancestor Route error, which could be a loader/action * error or a render error. This is intended to be called from your * ErrorBoundary/errorElement to display a proper error message. */ function useRouteError() { var _state$errors; let error = React.useContext(RouteErrorContext); let state = useDataRouterState(DataRouterStateHook.UseRouteError); let routeId = useCurrentRouteId(DataRouterStateHook.UseRouteError); // If this was a render error, we put it in a RouteError context inside // of RenderErrorBoundary if (error !== undefined) { return error; } // Otherwise look for errors from our data router state return (_state$errors = state.errors) == null ? void 0 : _state$errors[routeId]; } /** * Returns the happy-path data from the nearest ancestor `` value */ function useAsyncValue() { let value = React.useContext(AwaitContext); return value == null ? void 0 : value._data; } /** * Returns the error from the nearest ancestor `` value */ function useAsyncError() { let value = React.useContext(AwaitContext); return value == null ? void 0 : value._error; } let blockerId = 0; /** * Allow the application to block navigations within the SPA and present the * user a confirmation dialog to confirm the navigation. Mostly used to avoid * using half-filled form data. This does not handle hard-reloads or * cross-origin navigations. */ function useBlocker(shouldBlock) { let { router, basename } = useDataRouterContext(DataRouterHook.UseBlocker); let state = useDataRouterState(DataRouterStateHook.UseBlocker); let [blockerKey, setBlockerKey] = React.useState(""); let blockerFunction = React.useCallback(arg => { if (typeof shouldBlock !== "function") { return !!shouldBlock; } if (basename === "/") { return shouldBlock(arg); } // If they provided us a function and we've got an active basename, strip // it from the locations we expose to the user to match the behavior of // useLocation let { currentLocation, nextLocation, historyAction } = arg; return shouldBlock({ currentLocation: _extends({}, currentLocation, { pathname: stripBasename(currentLocation.pathname, basename) || currentLocation.pathname }), nextLocation: _extends({}, nextLocation, { pathname: stripBasename(nextLocation.pathname, basename) || nextLocation.pathname }), historyAction }); }, [basename, shouldBlock]); // This effect is in charge of blocker key assignment and deletion (which is // tightly coupled to the key) React.useEffect(() => { let key = String(++blockerId); setBlockerKey(key); return () => router.deleteBlocker(key); }, [router]); // This effect handles assigning the blockerFunction. This is to handle // unstable blocker function identities, and happens only after the prior // effect so we don't get an orphaned blockerFunction in the router with a // key of "". Until then we just have the IDLE_BLOCKER. React.useEffect(() => { if (blockerKey !== "") { router.getBlocker(blockerKey, blockerFunction); } }, [router, blockerKey, blockerFunction]); // Prefer the blocker from `state` not `router.state` since DataRouterContext // is memoized so this ensures we update on blocker state updates return blockerKey && state.blockers.has(blockerKey) ? state.blockers.get(blockerKey) : IDLE_BLOCKER; } /** * Stable version of useNavigate that is used when we are in the context of * a RouterProvider. */ function useNavigateStable() { let { router } = useDataRouterContext(DataRouterHook.UseNavigateStable); let id = useCurrentRouteId(DataRouterStateHook.UseNavigateStable); let activeRef = React.useRef(false); useIsomorphicLayoutEffect(() => { activeRef.current = true; }); let navigate = React.useCallback(function (to, options) { if (options === void 0) { options = {}; } process.env.NODE_ENV !== "production" ? UNSAFE_warning(activeRef.current, navigateEffectWarning) : void 0; // Short circuit here since if this happens on first render the navigate // is useless because we haven't wired up our router subscriber yet if (!activeRef.current) return; if (typeof to === "number") { router.navigate(to); } else { router.navigate(to, _extends({ fromRouteId: id }, options)); } }, [router, id]); return navigate; } const alreadyWarned = {}; function warningOnce(key, cond, message) { if (!cond && !alreadyWarned[key]) { alreadyWarned[key] = true; process.env.NODE_ENV !== "production" ? UNSAFE_warning(false, message) : void 0; } } /** Webpack + React 17 fails to compile on any of the following because webpack complains that `startTransition` doesn't exist in `React`: * import { startTransition } from "react" * import * as React from from "react"; "startTransition" in React ? React.startTransition(() => setState()) : setState() * import * as React from from "react"; "startTransition" in React ? React["startTransition"](() => setState()) : setState() Moving it to a constant such as the following solves the Webpack/React 17 issue: * import * as React from from "react"; const START_TRANSITION = "startTransition"; START_TRANSITION in React ? React[START_TRANSITION](() => setState()) : setState() However, that introduces webpack/terser minification issues in production builds in React 18 where minification/obfuscation ends up removing the call of React.startTransition entirely from the first half of the ternary. Grabbing this exported reference once up front resolves that issue. See https://github.com/remix-run/react-router/issues/10579 */ const START_TRANSITION = "startTransition"; const startTransitionImpl = React[START_TRANSITION]; /** * Given a Remix Router instance, render the appropriate UI */ function RouterProvider(_ref) { let { fallbackElement, router, future } = _ref; let [state, setStateImpl] = React.useState(router.state); let { v7_startTransition } = future || {}; let setState = React.useCallback(newState => { if (v7_startTransition && startTransitionImpl) { startTransitionImpl(() => setStateImpl(newState)); } else { setStateImpl(newState); } }, [setStateImpl, v7_startTransition]); // Need to use a layout effect here so we are subscribed early enough to // pick up on any render-driven redirects/navigations (useEffect/) React.useLayoutEffect(() => router.subscribe(setState), [router, setState]); React.useEffect(() => { process.env.NODE_ENV !== "production" ? UNSAFE_warning(fallbackElement == null || !router.future.v7_partialHydration, "`` is deprecated when using " + "`v7_partialHydration`, use a `HydrateFallback` component instead") : void 0; // Only log this once on initial mount // eslint-disable-next-line react-hooks/exhaustive-deps }, []); let navigator = React.useMemo(() => { return { createHref: router.createHref, encodeLocation: router.encodeLocation, go: n => router.navigate(n), push: (to, state, opts) => router.navigate(to, { state, preventScrollReset: opts == null ? void 0 : opts.preventScrollReset }), replace: (to, state, opts) => router.navigate(to, { replace: true, state, preventScrollReset: opts == null ? void 0 : opts.preventScrollReset }) }; }, [router]); let basename = router.basename || "/"; let dataRouterContext = React.useMemo(() => ({ router, navigator, static: false, basename }), [router, navigator, basename]); // The fragment and {null} here are important! We need them to keep React 18's // useId happy when we are server-rendering since we may have a