@tanstack/react-router
Advanced tools
+15
-18
@@ -19,2 +19,4 @@ "use client"; | ||
| //#region src/Match.tsx | ||
| var matchViewFieldsEqual = (a, b) => a.routeId === b.routeId && a._displayPending === b._displayPending; | ||
| var outletMatchSelectionEqual = (a, b) => a[0] === b[0] && a[1] === b[1]; | ||
| var Match = react.memo(function MatchImpl({ matchId }) { | ||
@@ -48,3 +50,3 @@ const router = require_useRouter.useRouter(); | ||
| const resetKey = (0, _tanstack_react_store.useStore)(router.stores.loadedAt, (loadedAt) => loadedAt); | ||
| const match = (0, _tanstack_react_store.useStore)(matchStore, (value) => value); | ||
| const match = (0, _tanstack_react_store.useStore)(matchStore, (value) => value, matchViewFieldsEqual); | ||
| return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(MatchView, { | ||
@@ -110,22 +112,17 @@ router, | ||
| }) | ||
| }), matchState.parentRouteId === _tanstack_router_core.rootRouteId ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(OnRendered, { resetKey }), router.options.scrollRestoration && (_tanstack_router_core_isServer.isServer ?? router.isServer) ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_scroll_restoration.ScrollRestoration, {}) : null] }) : null] }); | ||
| }), matchState.parentRouteId === _tanstack_router_core.rootRouteId ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(OnRendered, {}), router.options.scrollRestoration && (_tanstack_router_core_isServer.isServer ?? router.isServer) ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_scroll_restoration.ScrollRestoration, {}) : null] }) : null] }); | ||
| } | ||
| function OnRendered({ resetKey }) { | ||
| function OnRendered() { | ||
| const router = require_useRouter.useRouter(); | ||
| if (_tanstack_router_core_isServer.isServer ?? router.isServer) return null; | ||
| const prevHrefRef = react.useRef(void 0); | ||
| const prevResolvedLocationRef = react.useRef(); | ||
| require_utils.useLayoutEffect(() => { | ||
| const currentHref = router.latestLocation.href; | ||
| if (prevHrefRef.current === void 0 || prevHrefRef.current !== currentHref) { | ||
| router.emit({ | ||
| type: "onRendered", | ||
| ...(0, _tanstack_router_core.getLocationChangeInfo)(router.stores.location.get(), router.stores.resolvedLocation.get()) | ||
| }); | ||
| prevHrefRef.current = currentHref; | ||
| } | ||
| }, [ | ||
| router.latestLocation.state.__TSR_key, | ||
| resetKey, | ||
| router | ||
| ]); | ||
| const currentResolvedLocation = router.stores.resolvedLocation.get(); | ||
| const previousResolvedLocation = prevResolvedLocationRef.current; | ||
| if (currentResolvedLocation && (!previousResolvedLocation || previousResolvedLocation.href !== currentResolvedLocation.href)) router.emit({ | ||
| type: "onRendered", | ||
| ...(0, _tanstack_router_core.getLocationChangeInfo)(router.stores.location.get(), previousResolvedLocation ?? currentResolvedLocation) | ||
| }); | ||
| prevResolvedLocationRef.current = currentResolvedLocation; | ||
| }, [(0, _tanstack_react_store.useStore)(router.stores.resolvedLocation, (resolvedLocation) => resolvedLocation?.state.__TSR_key), router]); | ||
| return null; | ||
@@ -276,3 +273,3 @@ } | ||
| const parentMatchStore = matchId ? router.stores.matchStores.get(matchId) : void 0; | ||
| [routeId, parentGlobalNotFound] = (0, _tanstack_react_store.useStore)(parentMatchStore, (match) => [match?.routeId, match?.globalNotFound ?? false]); | ||
| [routeId, parentGlobalNotFound] = (0, _tanstack_react_store.useStore)(parentMatchStore, (match) => [match?.routeId, match?.globalNotFound ?? false], outletMatchSelectionEqual); | ||
| childMatchId = (0, _tanstack_react_store.useStore)(router.stores.matchesId, (ids) => { | ||
@@ -279,0 +276,0 @@ return ids[ids.findIndex((id) => id === matchId) + 1]; |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"Match.cjs","names":[],"sources":["../../src/Match.tsx"],"sourcesContent":["'use client'\n\nimport * as React from 'react'\nimport { useStore } from '@tanstack/react-store'\nimport {\n createControlledPromise,\n getLocationChangeInfo,\n invariant,\n isNotFound,\n isRedirect,\n rootRouteId,\n} from '@tanstack/router-core'\nimport { isServer } from '@tanstack/router-core/isServer'\nimport { CatchBoundary, ErrorComponent } from './CatchBoundary'\nimport { useRouter } from './useRouter'\nimport { CatchNotFound } from './not-found'\nimport { matchContext } from './matchContext'\nimport { SafeFragment } from './SafeFragment'\nimport { renderRouteNotFound } from './renderRouteNotFound'\nimport { ScrollRestoration } from './scroll-restoration'\nimport { ClientOnly } from './ClientOnly'\nimport { useLayoutEffect } from './utils'\nimport type { AnyRoute, RootRouteOptions } from '@tanstack/router-core'\n\nexport const Match = React.memo(function MatchImpl({\n matchId,\n}: {\n matchId: string\n}) {\n const router = useRouter()\n\n if (isServer ?? router.isServer) {\n const match = router.stores.matchStores.get(matchId)?.get()\n if (!match) {\n if (process.env.NODE_ENV !== 'production') {\n throw new Error(\n `Invariant failed: Could not find match for matchId \"${matchId}\". Please file an issue!`,\n )\n }\n\n invariant()\n }\n\n const routeId = match.routeId as string\n const parentRouteId = (router.routesById[routeId] as AnyRoute).parentRoute\n ?.id\n\n return (\n <MatchView\n router={router}\n matchId={matchId}\n resetKey={router.stores.loadedAt.get()}\n matchState={{\n routeId,\n ssr: match.ssr,\n _displayPending: match._displayPending,\n parentRouteId,\n }}\n />\n )\n }\n\n // Subscribe directly to the match store from the pool.\n // The matchId prop is stable for this component's lifetime (set by Outlet),\n // and reconcileMatchPool reuses stores for the same matchId.\n\n const matchStore = router.stores.matchStores.get(matchId)\n if (!matchStore) {\n if (process.env.NODE_ENV !== 'production') {\n throw new Error(\n `Invariant failed: Could not find match for matchId \"${matchId}\". Please file an issue!`,\n )\n }\n\n invariant()\n }\n // eslint-disable-next-line react-hooks/rules-of-hooks\n const resetKey = useStore(router.stores.loadedAt, (loadedAt) => loadedAt)\n // eslint-disable-next-line react-hooks/rules-of-hooks\n const match = useStore(matchStore, (value) => value)\n // eslint-disable-next-line react-hooks/rules-of-hooks\n const matchState = React.useMemo(() => {\n const routeId = match.routeId as string\n const parentRouteId = (router.routesById[routeId] as AnyRoute).parentRoute\n ?.id\n\n return {\n routeId,\n ssr: match.ssr,\n _displayPending: match._displayPending,\n parentRouteId: parentRouteId as string | undefined,\n } satisfies MatchViewState\n }, [match._displayPending, match.routeId, match.ssr, router.routesById])\n\n return (\n <MatchView\n router={router}\n matchId={matchId}\n resetKey={resetKey}\n matchState={matchState}\n />\n )\n})\n\ntype MatchViewState = {\n routeId: string\n ssr: boolean | 'data-only' | undefined\n _displayPending: boolean | undefined\n parentRouteId: string | undefined\n}\n\nfunction MatchView({\n router,\n matchId,\n resetKey,\n matchState,\n}: {\n router: ReturnType<typeof useRouter>\n matchId: string\n resetKey: number\n matchState: MatchViewState\n}) {\n const route: AnyRoute = router.routesById[matchState.routeId]\n\n const PendingComponent =\n route.options.pendingComponent ?? router.options.defaultPendingComponent\n\n const pendingElement = PendingComponent ? <PendingComponent /> : null\n\n const routeErrorComponent =\n route.options.errorComponent ?? router.options.defaultErrorComponent\n\n const routeOnCatch = route.options.onCatch ?? router.options.defaultOnCatch\n\n const routeNotFoundComponent = route.isRoot\n ? // If it's the root route, use the globalNotFound option, with fallback to the notFoundRoute's component\n (route.options.notFoundComponent ??\n router.options.notFoundRoute?.options.component)\n : route.options.notFoundComponent\n\n const resolvedNoSsr =\n matchState.ssr === false || matchState.ssr === 'data-only'\n const ResolvedSuspenseBoundary =\n // If we're on the root route, allow forcefully wrapping in suspense\n (!route.isRoot || route.options.wrapInSuspense || resolvedNoSsr) &&\n (route.options.wrapInSuspense ??\n PendingComponent ??\n ((route.options.errorComponent as any)?.preload || resolvedNoSsr))\n ? React.Suspense\n : SafeFragment\n\n const ResolvedCatchBoundary = routeErrorComponent\n ? CatchBoundary\n : SafeFragment\n\n const ResolvedNotFoundBoundary = routeNotFoundComponent\n ? CatchNotFound\n : SafeFragment\n\n const ShellComponent = route.isRoot\n ? ((route.options as RootRouteOptions).shellComponent ?? SafeFragment)\n : SafeFragment\n return (\n <ShellComponent>\n <matchContext.Provider value={matchId}>\n <ResolvedSuspenseBoundary fallback={pendingElement}>\n <ResolvedCatchBoundary\n getResetKey={() => resetKey}\n errorComponent={routeErrorComponent || ErrorComponent}\n onCatch={(error, errorInfo) => {\n // Forward not found errors (we don't want to show the error component for these)\n if (isNotFound(error)) {\n error.routeId ??= matchState.routeId as any\n throw error\n }\n if (process.env.NODE_ENV !== 'production') {\n console.warn(`Warning: Error in route match: ${matchId}`)\n }\n routeOnCatch?.(error, errorInfo)\n }}\n >\n <ResolvedNotFoundBoundary\n fallback={(error) => {\n error.routeId ??= matchState.routeId as any\n\n // If the current not found handler doesn't exist or it has a\n // route ID which doesn't match the current route, rethrow the error\n if (\n !routeNotFoundComponent ||\n (error.routeId && error.routeId !== matchState.routeId) ||\n (!error.routeId && !route.isRoot)\n )\n throw error\n\n return React.createElement(routeNotFoundComponent, error as any)\n }}\n >\n {resolvedNoSsr || matchState._displayPending ? (\n <ClientOnly fallback={pendingElement}>\n <MatchInner matchId={matchId} />\n </ClientOnly>\n ) : (\n <MatchInner matchId={matchId} />\n )}\n </ResolvedNotFoundBoundary>\n </ResolvedCatchBoundary>\n </ResolvedSuspenseBoundary>\n </matchContext.Provider>\n {matchState.parentRouteId === rootRouteId ? (\n <>\n <OnRendered resetKey={resetKey} />\n {router.options.scrollRestoration && (isServer ?? router.isServer) ? (\n <ScrollRestoration />\n ) : null}\n </>\n ) : null}\n </ShellComponent>\n )\n}\n\n// On Rendered can't happen above the root layout because it needs to run after\n// the route subtree has committed below the root layout. Keeping it here lets\n// us fire onRendered even after a hydration mismatch above the root layout\n// (like bad head/link tags, which is common).\nfunction OnRendered({ resetKey }: { resetKey: number }) {\n const router = useRouter()\n\n if (isServer ?? router.isServer) {\n return null\n }\n\n // eslint-disable-next-line react-hooks/rules-of-hooks\n const prevHrefRef = React.useRef<string | undefined>(undefined)\n\n // eslint-disable-next-line react-hooks/rules-of-hooks\n useLayoutEffect(() => {\n const currentHref = router.latestLocation.href\n\n if (\n prevHrefRef.current === undefined ||\n prevHrefRef.current !== currentHref\n ) {\n router.emit({\n type: 'onRendered',\n ...getLocationChangeInfo(\n router.stores.location.get(),\n router.stores.resolvedLocation.get(),\n ),\n })\n prevHrefRef.current = currentHref\n }\n }, [router.latestLocation.state.__TSR_key, resetKey, router])\n\n return null\n}\n\nexport const MatchInner = React.memo(function MatchInnerImpl({\n matchId,\n}: {\n matchId: string\n}): any {\n const router = useRouter()\n\n const getMatchPromise = (\n match: {\n id: string\n _nonReactive: {\n displayPendingPromise?: Promise<void>\n minPendingPromise?: Promise<void>\n loadPromise?: Promise<void>\n }\n },\n key: 'displayPendingPromise' | 'minPendingPromise' | 'loadPromise',\n ) => {\n return (\n router.getMatch(match.id)?._nonReactive[key] ?? match._nonReactive[key]\n )\n }\n\n if (isServer ?? router.isServer) {\n const match = router.stores.matchStores.get(matchId)?.get()\n if (!match) {\n if (process.env.NODE_ENV !== 'production') {\n throw new Error(\n `Invariant failed: Could not find match for matchId \"${matchId}\". Please file an issue!`,\n )\n }\n\n invariant()\n }\n\n const routeId = match.routeId as string\n const route = router.routesById[routeId] as AnyRoute\n const remountFn =\n (router.routesById[routeId] as AnyRoute).options.remountDeps ??\n router.options.defaultRemountDeps\n const remountDeps = remountFn?.({\n routeId,\n loaderDeps: match.loaderDeps,\n params: match._strictParams,\n search: match._strictSearch,\n })\n const key = remountDeps ? JSON.stringify(remountDeps) : undefined\n const Comp = route.options.component ?? router.options.defaultComponent\n const out = Comp ? <Comp key={key} /> : <Outlet />\n\n if (match._displayPending) {\n throw getMatchPromise(match, 'displayPendingPromise')\n }\n\n if (match._forcePending) {\n throw getMatchPromise(match, 'minPendingPromise')\n }\n\n if (match.status === 'pending') {\n throw getMatchPromise(match, 'loadPromise')\n }\n\n if (match.status === 'notFound') {\n if (!isNotFound(match.error)) {\n if (process.env.NODE_ENV !== 'production') {\n throw new Error('Invariant failed: Expected a notFound error')\n }\n\n invariant()\n }\n return renderRouteNotFound(router, route, match.error)\n }\n\n if (match.status === 'redirected') {\n if (!isRedirect(match.error)) {\n if (process.env.NODE_ENV !== 'production') {\n throw new Error('Invariant failed: Expected a redirect error')\n }\n\n invariant()\n }\n throw getMatchPromise(match, 'loadPromise')\n }\n\n if (match.status === 'error') {\n const RouteErrorComponent =\n (route.options.errorComponent ??\n router.options.defaultErrorComponent) ||\n ErrorComponent\n return (\n <RouteErrorComponent\n error={match.error as any}\n reset={undefined as any}\n info={{\n componentStack: '',\n }}\n />\n )\n }\n\n return out\n }\n\n const matchStore = router.stores.matchStores.get(matchId)\n if (!matchStore) {\n if (process.env.NODE_ENV !== 'production') {\n throw new Error(\n `Invariant failed: Could not find match for matchId \"${matchId}\". Please file an issue!`,\n )\n }\n\n invariant()\n }\n // eslint-disable-next-line react-hooks/rules-of-hooks\n const match = useStore(matchStore, (value) => value)\n const routeId = match.routeId as string\n const route = router.routesById[routeId] as AnyRoute\n // eslint-disable-next-line react-hooks/rules-of-hooks\n const key = React.useMemo(() => {\n const remountFn =\n (router.routesById[routeId] as AnyRoute).options.remountDeps ??\n router.options.defaultRemountDeps\n const remountDeps = remountFn?.({\n routeId,\n loaderDeps: match.loaderDeps,\n params: match._strictParams,\n search: match._strictSearch,\n })\n return remountDeps ? JSON.stringify(remountDeps) : undefined\n }, [\n routeId,\n match.loaderDeps,\n match._strictParams,\n match._strictSearch,\n router.options.defaultRemountDeps,\n router.routesById,\n ])\n\n // eslint-disable-next-line react-hooks/rules-of-hooks\n const out = React.useMemo(() => {\n const Comp = route.options.component ?? router.options.defaultComponent\n if (Comp) {\n return <Comp key={key} />\n }\n return <Outlet />\n }, [key, route.options.component, router.options.defaultComponent])\n\n if (match._displayPending) {\n throw getMatchPromise(match, 'displayPendingPromise')\n }\n\n if (match._forcePending) {\n throw getMatchPromise(match, 'minPendingPromise')\n }\n\n // see also hydrate() in packages/router-core/src/ssr/ssr-client.ts\n if (match.status === 'pending') {\n // We're pending, and if we have a minPendingMs, we need to wait for it\n const pendingMinMs =\n route.options.pendingMinMs ?? router.options.defaultPendingMinMs\n if (pendingMinMs) {\n const routerMatch = router.getMatch(match.id)\n if (routerMatch && !routerMatch._nonReactive.minPendingPromise) {\n // Create a promise that will resolve after the minPendingMs\n if (!(isServer ?? router.isServer)) {\n const minPendingPromise = createControlledPromise<void>()\n\n routerMatch._nonReactive.minPendingPromise = minPendingPromise\n\n setTimeout(() => {\n minPendingPromise.resolve()\n // We've handled the minPendingPromise, so we can delete it\n routerMatch._nonReactive.minPendingPromise = undefined\n }, pendingMinMs)\n }\n }\n }\n throw getMatchPromise(match, 'loadPromise')\n }\n\n if (match.status === 'notFound') {\n if (!isNotFound(match.error)) {\n if (process.env.NODE_ENV !== 'production') {\n throw new Error('Invariant failed: Expected a notFound error')\n }\n\n invariant()\n }\n return renderRouteNotFound(router, route, match.error)\n }\n\n if (match.status === 'redirected') {\n // A match can be observed as redirected during an in-flight transition,\n // especially when pending UI is already rendering. Suspend on the match's\n // load promise so React can abandon this stale render and continue the\n // redirect transition.\n if (!isRedirect(match.error)) {\n if (process.env.NODE_ENV !== 'production') {\n throw new Error('Invariant failed: Expected a redirect error')\n }\n\n invariant()\n }\n\n throw getMatchPromise(match, 'loadPromise')\n }\n\n if (match.status === 'error') {\n // If we're on the server, we need to use React's new and super\n // wonky api for throwing errors from a server side render inside\n // of a suspense boundary. This is the only way to get\n // renderToPipeableStream to not hang indefinitely.\n // We'll serialize the error and rethrow it on the client.\n if (isServer ?? router.isServer) {\n const RouteErrorComponent =\n (route.options.errorComponent ??\n router.options.defaultErrorComponent) ||\n ErrorComponent\n return (\n <RouteErrorComponent\n error={match.error as any}\n reset={undefined as any}\n info={{\n componentStack: '',\n }}\n />\n )\n }\n\n throw match.error\n }\n\n return out\n})\n\n/**\n * Render the next child match in the route tree. Typically used inside\n * a route component to render nested routes.\n *\n * @link https://tanstack.com/router/latest/docs/framework/react/api/router/outletComponent\n */\nexport const Outlet = React.memo(function OutletImpl() {\n const router = useRouter()\n const matchId = React.useContext(matchContext)\n\n let routeId: string | undefined\n let parentGlobalNotFound = false\n let childMatchId: string | undefined\n\n if (isServer ?? router.isServer) {\n const matches = router.stores.matches.get()\n const parentIndex = matchId\n ? matches.findIndex((match) => match.id === matchId)\n : -1\n const parentMatch = parentIndex >= 0 ? matches[parentIndex] : undefined\n routeId = parentMatch?.routeId as string | undefined\n parentGlobalNotFound = parentMatch?.globalNotFound ?? false\n childMatchId =\n parentIndex >= 0 ? (matches[parentIndex + 1]?.id as string) : undefined\n } else {\n // Subscribe directly to the match store from the pool instead of\n // the two-level byId → matchStore pattern.\n const parentMatchStore = matchId\n ? router.stores.matchStores.get(matchId)\n : undefined\n\n // eslint-disable-next-line react-hooks/rules-of-hooks\n ;[routeId, parentGlobalNotFound] = useStore(parentMatchStore, (match) => [\n match?.routeId as string | undefined,\n match?.globalNotFound ?? false,\n ])\n\n // eslint-disable-next-line react-hooks/rules-of-hooks\n childMatchId = useStore(router.stores.matchesId, (ids) => {\n const index = ids.findIndex((id) => id === matchId)\n return ids[index + 1]\n })\n }\n\n const route = routeId ? router.routesById[routeId] : undefined\n\n const pendingElement = router.options.defaultPendingComponent ? (\n <router.options.defaultPendingComponent />\n ) : null\n\n if (parentGlobalNotFound) {\n if (!route) {\n if (process.env.NODE_ENV !== 'production') {\n throw new Error(\n 'Invariant failed: Could not resolve route for Outlet render',\n )\n }\n\n invariant()\n }\n return renderRouteNotFound(router, route, undefined)\n }\n\n if (!childMatchId) {\n return null\n }\n\n const nextMatch = <Match matchId={childMatchId} />\n\n if (routeId === rootRouteId) {\n return (\n <React.Suspense fallback={pendingElement}>{nextMatch}</React.Suspense>\n )\n }\n\n return nextMatch\n})\n"],"mappings":"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"} | ||
| {"version":3,"file":"Match.cjs","names":[],"sources":["../../src/Match.tsx"],"sourcesContent":["'use client'\n\nimport * as React from 'react'\nimport { useStore } from '@tanstack/react-store'\nimport {\n createControlledPromise,\n getLocationChangeInfo,\n invariant,\n isNotFound,\n isRedirect,\n rootRouteId,\n} from '@tanstack/router-core'\nimport { isServer } from '@tanstack/router-core/isServer'\nimport { CatchBoundary, ErrorComponent } from './CatchBoundary'\nimport { useRouter } from './useRouter'\nimport { CatchNotFound } from './not-found'\nimport { matchContext } from './matchContext'\nimport { SafeFragment } from './SafeFragment'\nimport { renderRouteNotFound } from './renderRouteNotFound'\nimport { ScrollRestoration } from './scroll-restoration'\nimport { ClientOnly } from './ClientOnly'\nimport { useLayoutEffect } from './utils'\nimport type {\n AnyRoute,\n AnyRouteMatch,\n ParsedLocation,\n RootRouteOptions,\n} from '@tanstack/router-core'\n\ntype OutletMatchSelection = [\n routeId: string | undefined,\n parentGlobalNotFound: boolean,\n]\n\nconst matchViewFieldsEqual = (a: AnyRouteMatch, b: AnyRouteMatch) =>\n a.routeId === b.routeId && a._displayPending === b._displayPending\n\nconst outletMatchSelectionEqual = (\n a: OutletMatchSelection,\n b: OutletMatchSelection,\n) => a[0] === b[0] && a[1] === b[1]\n\nexport const Match = React.memo(function MatchImpl({\n matchId,\n}: {\n matchId: string\n}) {\n const router = useRouter()\n\n if (isServer ?? router.isServer) {\n const match = router.stores.matchStores.get(matchId)?.get()\n if (!match) {\n if (process.env.NODE_ENV !== 'production') {\n throw new Error(\n `Invariant failed: Could not find match for matchId \"${matchId}\". Please file an issue!`,\n )\n }\n\n invariant()\n }\n\n const routeId = match.routeId as string\n const parentRouteId = (router.routesById[routeId] as AnyRoute).parentRoute\n ?.id\n\n return (\n <MatchView\n router={router}\n matchId={matchId}\n resetKey={router.stores.loadedAt.get()}\n matchState={{\n routeId,\n ssr: match.ssr,\n _displayPending: match._displayPending,\n parentRouteId,\n }}\n />\n )\n }\n\n // Subscribe directly to the match store from the pool.\n // The matchId prop is stable for this component's lifetime (set by Outlet),\n // and reconcileMatchPool reuses stores for the same matchId.\n\n const matchStore = router.stores.matchStores.get(matchId)\n if (!matchStore) {\n if (process.env.NODE_ENV !== 'production') {\n throw new Error(\n `Invariant failed: Could not find match for matchId \"${matchId}\". Please file an issue!`,\n )\n }\n\n invariant()\n }\n // eslint-disable-next-line react-hooks/rules-of-hooks\n const resetKey = useStore(router.stores.loadedAt, (loadedAt) => loadedAt)\n // eslint-disable-next-line react-hooks/rules-of-hooks\n const match = useStore(matchStore, (value) => value, matchViewFieldsEqual)\n // eslint-disable-next-line react-hooks/rules-of-hooks\n const matchState = React.useMemo(() => {\n const routeId = match.routeId as string\n const parentRouteId = (router.routesById[routeId] as AnyRoute).parentRoute\n ?.id\n\n return {\n routeId,\n ssr: match.ssr,\n _displayPending: match._displayPending,\n parentRouteId: parentRouteId as string | undefined,\n } satisfies MatchViewState\n }, [match._displayPending, match.routeId, match.ssr, router.routesById])\n\n return (\n <MatchView\n router={router}\n matchId={matchId}\n resetKey={resetKey}\n matchState={matchState}\n />\n )\n})\n\ntype MatchViewState = {\n routeId: string\n ssr: boolean | 'data-only' | undefined\n _displayPending: boolean | undefined\n parentRouteId: string | undefined\n}\n\nfunction MatchView({\n router,\n matchId,\n resetKey,\n matchState,\n}: {\n router: ReturnType<typeof useRouter>\n matchId: string\n resetKey: number\n matchState: MatchViewState\n}) {\n const route: AnyRoute = router.routesById[matchState.routeId]\n\n const PendingComponent =\n route.options.pendingComponent ?? router.options.defaultPendingComponent\n\n const pendingElement = PendingComponent ? <PendingComponent /> : null\n\n const routeErrorComponent =\n route.options.errorComponent ?? router.options.defaultErrorComponent\n\n const routeOnCatch = route.options.onCatch ?? router.options.defaultOnCatch\n\n const routeNotFoundComponent = route.isRoot\n ? // If it's the root route, use the globalNotFound option, with fallback to the notFoundRoute's component\n (route.options.notFoundComponent ??\n router.options.notFoundRoute?.options.component)\n : route.options.notFoundComponent\n\n const resolvedNoSsr =\n matchState.ssr === false || matchState.ssr === 'data-only'\n const ResolvedSuspenseBoundary =\n // If we're on the root route, allow forcefully wrapping in suspense\n (!route.isRoot || route.options.wrapInSuspense || resolvedNoSsr) &&\n (route.options.wrapInSuspense ??\n PendingComponent ??\n ((route.options.errorComponent as any)?.preload || resolvedNoSsr))\n ? React.Suspense\n : SafeFragment\n\n const ResolvedCatchBoundary = routeErrorComponent\n ? CatchBoundary\n : SafeFragment\n\n const ResolvedNotFoundBoundary = routeNotFoundComponent\n ? CatchNotFound\n : SafeFragment\n\n const ShellComponent = route.isRoot\n ? ((route.options as RootRouteOptions).shellComponent ?? SafeFragment)\n : SafeFragment\n return (\n <ShellComponent>\n <matchContext.Provider value={matchId}>\n <ResolvedSuspenseBoundary fallback={pendingElement}>\n <ResolvedCatchBoundary\n getResetKey={() => resetKey}\n errorComponent={routeErrorComponent || ErrorComponent}\n onCatch={(error, errorInfo) => {\n // Forward not found errors (we don't want to show the error component for these)\n if (isNotFound(error)) {\n error.routeId ??= matchState.routeId as any\n throw error\n }\n if (process.env.NODE_ENV !== 'production') {\n console.warn(`Warning: Error in route match: ${matchId}`)\n }\n routeOnCatch?.(error, errorInfo)\n }}\n >\n <ResolvedNotFoundBoundary\n fallback={(error) => {\n error.routeId ??= matchState.routeId as any\n\n // If the current not found handler doesn't exist or it has a\n // route ID which doesn't match the current route, rethrow the error\n if (\n !routeNotFoundComponent ||\n (error.routeId && error.routeId !== matchState.routeId) ||\n (!error.routeId && !route.isRoot)\n )\n throw error\n\n return React.createElement(routeNotFoundComponent, error as any)\n }}\n >\n {resolvedNoSsr || matchState._displayPending ? (\n <ClientOnly fallback={pendingElement}>\n <MatchInner matchId={matchId} />\n </ClientOnly>\n ) : (\n <MatchInner matchId={matchId} />\n )}\n </ResolvedNotFoundBoundary>\n </ResolvedCatchBoundary>\n </ResolvedSuspenseBoundary>\n </matchContext.Provider>\n {matchState.parentRouteId === rootRouteId ? (\n <>\n <OnRendered />\n {router.options.scrollRestoration && (isServer ?? router.isServer) ? (\n <ScrollRestoration />\n ) : null}\n </>\n ) : null}\n </ShellComponent>\n )\n}\n\n// On Rendered can't happen above the root layout because it needs to run after\n// the route subtree has committed below the root layout. Keeping it here lets\n// us fire onRendered even after a hydration mismatch above the root layout\n// (like bad head/link tags, which is common).\nfunction OnRendered() {\n const router = useRouter()\n\n if (isServer ?? router.isServer) {\n return null\n }\n\n // Track the resolvedLocation as of the last render so that onRendered can\n // report the correct fromLocation. By the time this effect fires,\n // resolvedLocation has already been updated to the new location by\n // Transitioner, so we cannot use router.stores.resolvedLocation.get()\n // directly as the fromLocation.\n // @ts-expect-error -- init to `undefined` but don't write `undefined` to shave bytes\n // eslint-disable-next-line react-hooks/rules-of-hooks\n const prevResolvedLocationRef = React.useRef<\n ParsedLocation<any> | undefined\n >()\n // eslint-disable-next-line react-hooks/rules-of-hooks\n const renderedLocationKey = useStore(\n router.stores.resolvedLocation,\n (resolvedLocation) => resolvedLocation?.state.__TSR_key,\n )\n\n // eslint-disable-next-line react-hooks/rules-of-hooks\n useLayoutEffect(() => {\n const currentResolvedLocation = router.stores.resolvedLocation.get()\n const previousResolvedLocation = prevResolvedLocationRef.current\n\n if (\n currentResolvedLocation &&\n (!previousResolvedLocation ||\n previousResolvedLocation.href !== currentResolvedLocation.href)\n ) {\n router.emit({\n type: 'onRendered',\n ...getLocationChangeInfo(\n router.stores.location.get(),\n previousResolvedLocation ?? currentResolvedLocation,\n ),\n })\n }\n prevResolvedLocationRef.current = currentResolvedLocation\n }, [renderedLocationKey, router])\n\n return null\n}\n\nexport const MatchInner = React.memo(function MatchInnerImpl({\n matchId,\n}: {\n matchId: string\n}): any {\n const router = useRouter()\n\n const getMatchPromise = (\n match: {\n id: string\n _nonReactive: {\n displayPendingPromise?: Promise<void>\n minPendingPromise?: Promise<void>\n loadPromise?: Promise<void>\n }\n },\n key: 'displayPendingPromise' | 'minPendingPromise' | 'loadPromise',\n ) => {\n return (\n router.getMatch(match.id)?._nonReactive[key] ?? match._nonReactive[key]\n )\n }\n\n if (isServer ?? router.isServer) {\n const match = router.stores.matchStores.get(matchId)?.get()\n if (!match) {\n if (process.env.NODE_ENV !== 'production') {\n throw new Error(\n `Invariant failed: Could not find match for matchId \"${matchId}\". Please file an issue!`,\n )\n }\n\n invariant()\n }\n\n const routeId = match.routeId as string\n const route = router.routesById[routeId] as AnyRoute\n const remountFn =\n (router.routesById[routeId] as AnyRoute).options.remountDeps ??\n router.options.defaultRemountDeps\n const remountDeps = remountFn?.({\n routeId,\n loaderDeps: match.loaderDeps,\n params: match._strictParams,\n search: match._strictSearch,\n })\n const key = remountDeps ? JSON.stringify(remountDeps) : undefined\n const Comp = route.options.component ?? router.options.defaultComponent\n const out = Comp ? <Comp key={key} /> : <Outlet />\n\n if (match._displayPending) {\n throw getMatchPromise(match, 'displayPendingPromise')\n }\n\n if (match._forcePending) {\n throw getMatchPromise(match, 'minPendingPromise')\n }\n\n if (match.status === 'pending') {\n throw getMatchPromise(match, 'loadPromise')\n }\n\n if (match.status === 'notFound') {\n if (!isNotFound(match.error)) {\n if (process.env.NODE_ENV !== 'production') {\n throw new Error('Invariant failed: Expected a notFound error')\n }\n\n invariant()\n }\n return renderRouteNotFound(router, route, match.error)\n }\n\n if (match.status === 'redirected') {\n if (!isRedirect(match.error)) {\n if (process.env.NODE_ENV !== 'production') {\n throw new Error('Invariant failed: Expected a redirect error')\n }\n\n invariant()\n }\n throw getMatchPromise(match, 'loadPromise')\n }\n\n if (match.status === 'error') {\n const RouteErrorComponent =\n (route.options.errorComponent ??\n router.options.defaultErrorComponent) ||\n ErrorComponent\n return (\n <RouteErrorComponent\n error={match.error as any}\n reset={undefined as any}\n info={{\n componentStack: '',\n }}\n />\n )\n }\n\n return out\n }\n\n const matchStore = router.stores.matchStores.get(matchId)\n if (!matchStore) {\n if (process.env.NODE_ENV !== 'production') {\n throw new Error(\n `Invariant failed: Could not find match for matchId \"${matchId}\". Please file an issue!`,\n )\n }\n\n invariant()\n }\n // eslint-disable-next-line react-hooks/rules-of-hooks\n const match = useStore(matchStore, (value) => value)\n const routeId = match.routeId as string\n const route = router.routesById[routeId] as AnyRoute\n // eslint-disable-next-line react-hooks/rules-of-hooks\n const key = React.useMemo(() => {\n const remountFn =\n (router.routesById[routeId] as AnyRoute).options.remountDeps ??\n router.options.defaultRemountDeps\n const remountDeps = remountFn?.({\n routeId,\n loaderDeps: match.loaderDeps,\n params: match._strictParams,\n search: match._strictSearch,\n })\n return remountDeps ? JSON.stringify(remountDeps) : undefined\n }, [\n routeId,\n match.loaderDeps,\n match._strictParams,\n match._strictSearch,\n router.options.defaultRemountDeps,\n router.routesById,\n ])\n\n // eslint-disable-next-line react-hooks/rules-of-hooks\n const out = React.useMemo(() => {\n const Comp = route.options.component ?? router.options.defaultComponent\n if (Comp) {\n return <Comp key={key} />\n }\n return <Outlet />\n }, [key, route.options.component, router.options.defaultComponent])\n\n if (match._displayPending) {\n throw getMatchPromise(match, 'displayPendingPromise')\n }\n\n if (match._forcePending) {\n throw getMatchPromise(match, 'minPendingPromise')\n }\n\n // see also hydrate() in packages/router-core/src/ssr/ssr-client.ts\n if (match.status === 'pending') {\n // We're pending, and if we have a minPendingMs, we need to wait for it\n const pendingMinMs =\n route.options.pendingMinMs ?? router.options.defaultPendingMinMs\n if (pendingMinMs) {\n const routerMatch = router.getMatch(match.id)\n if (routerMatch && !routerMatch._nonReactive.minPendingPromise) {\n // Create a promise that will resolve after the minPendingMs\n if (!(isServer ?? router.isServer)) {\n const minPendingPromise = createControlledPromise<void>()\n\n routerMatch._nonReactive.minPendingPromise = minPendingPromise\n\n setTimeout(() => {\n minPendingPromise.resolve()\n // We've handled the minPendingPromise, so we can delete it\n routerMatch._nonReactive.minPendingPromise = undefined\n }, pendingMinMs)\n }\n }\n }\n throw getMatchPromise(match, 'loadPromise')\n }\n\n if (match.status === 'notFound') {\n if (!isNotFound(match.error)) {\n if (process.env.NODE_ENV !== 'production') {\n throw new Error('Invariant failed: Expected a notFound error')\n }\n\n invariant()\n }\n return renderRouteNotFound(router, route, match.error)\n }\n\n if (match.status === 'redirected') {\n // A match can be observed as redirected during an in-flight transition,\n // especially when pending UI is already rendering. Suspend on the match's\n // load promise so React can abandon this stale render and continue the\n // redirect transition.\n if (!isRedirect(match.error)) {\n if (process.env.NODE_ENV !== 'production') {\n throw new Error('Invariant failed: Expected a redirect error')\n }\n\n invariant()\n }\n\n throw getMatchPromise(match, 'loadPromise')\n }\n\n if (match.status === 'error') {\n // If we're on the server, we need to use React's new and super\n // wonky api for throwing errors from a server side render inside\n // of a suspense boundary. This is the only way to get\n // renderToPipeableStream to not hang indefinitely.\n // We'll serialize the error and rethrow it on the client.\n if (isServer ?? router.isServer) {\n const RouteErrorComponent =\n (route.options.errorComponent ??\n router.options.defaultErrorComponent) ||\n ErrorComponent\n return (\n <RouteErrorComponent\n error={match.error as any}\n reset={undefined as any}\n info={{\n componentStack: '',\n }}\n />\n )\n }\n\n throw match.error\n }\n\n return out\n})\n\n/**\n * Render the next child match in the route tree. Typically used inside\n * a route component to render nested routes.\n *\n * @link https://tanstack.com/router/latest/docs/framework/react/api/router/outletComponent\n */\nexport const Outlet = React.memo(function OutletImpl() {\n const router = useRouter()\n const matchId = React.useContext(matchContext)\n\n let routeId: string | undefined\n let parentGlobalNotFound = false\n let childMatchId: string | undefined\n\n if (isServer ?? router.isServer) {\n const matches = router.stores.matches.get()\n const parentIndex = matchId\n ? matches.findIndex((match) => match.id === matchId)\n : -1\n const parentMatch = parentIndex >= 0 ? matches[parentIndex] : undefined\n routeId = parentMatch?.routeId as string | undefined\n parentGlobalNotFound = parentMatch?.globalNotFound ?? false\n childMatchId =\n parentIndex >= 0 ? (matches[parentIndex + 1]?.id as string) : undefined\n } else {\n // Subscribe directly to the match store from the pool instead of\n // the two-level byId → matchStore pattern.\n const parentMatchStore = matchId\n ? router.stores.matchStores.get(matchId)\n : undefined\n\n // eslint-disable-next-line react-hooks/rules-of-hooks\n ;[routeId, parentGlobalNotFound] = useStore(\n parentMatchStore,\n (match): OutletMatchSelection => [\n match?.routeId as string | undefined,\n match?.globalNotFound ?? false,\n ],\n outletMatchSelectionEqual,\n )\n\n // eslint-disable-next-line react-hooks/rules-of-hooks\n childMatchId = useStore(router.stores.matchesId, (ids) => {\n const index = ids.findIndex((id) => id === matchId)\n return ids[index + 1]\n })\n }\n\n const route = routeId ? router.routesById[routeId] : undefined\n\n const pendingElement = router.options.defaultPendingComponent ? (\n <router.options.defaultPendingComponent />\n ) : null\n\n if (parentGlobalNotFound) {\n if (!route) {\n if (process.env.NODE_ENV !== 'production') {\n throw new Error(\n 'Invariant failed: Could not resolve route for Outlet render',\n )\n }\n\n invariant()\n }\n return renderRouteNotFound(router, route, undefined)\n }\n\n if (!childMatchId) {\n return null\n }\n\n const nextMatch = <Match matchId={childMatchId} />\n\n if (routeId === rootRouteId) {\n return (\n <React.Suspense fallback={pendingElement}>{nextMatch}</React.Suspense>\n )\n }\n\n return nextMatch\n})\n"],"mappings":"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"} |
+2
-10
@@ -6,2 +6,3 @@ "use client"; | ||
| const require_useRouter = require("./useRouter.cjs"); | ||
| const require_useMatch = require("./useMatch.cjs"); | ||
| const require_Transitioner = require("./Transitioner.cjs"); | ||
@@ -89,3 +90,2 @@ const require_SafeFragment = require("./SafeFragment.cjs"); | ||
| const router = require_useRouter.useRouter(); | ||
| const previousResult = react.useRef(void 0); | ||
| if (_tanstack_router_core_isServer.isServer ?? router.isServer) { | ||
@@ -95,11 +95,3 @@ const matches = router.stores.matches.get(); | ||
| } | ||
| return (0, _tanstack_react_store.useStore)(router.stores.matches, (matches) => { | ||
| const selected = opts?.select ? opts.select(matches) : matches; | ||
| if (opts?.structuralSharing ?? router.options.defaultStructuralSharing) { | ||
| const shared = (0, _tanstack_router_core.replaceEqualDeep)(previousResult.current, selected); | ||
| previousResult.current = shared; | ||
| return shared; | ||
| } | ||
| return selected; | ||
| }); | ||
| return (0, _tanstack_react_store.useStore)(router.stores.matches, require_useMatch.useStructuralSharing(opts, router)); | ||
| } | ||
@@ -106,0 +98,0 @@ /** |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"Matches.cjs","names":[],"sources":["../../src/Matches.tsx"],"sourcesContent":["'use client'\n\nimport * as React from 'react'\nimport { useStore } from '@tanstack/react-store'\nimport { replaceEqualDeep, rootRouteId } from '@tanstack/router-core'\nimport { isServer } from '@tanstack/router-core/isServer'\nimport { CatchBoundary, ErrorComponent } from './CatchBoundary'\nimport { useRouter } from './useRouter'\nimport { Transitioner } from './Transitioner'\nimport { matchContext } from './matchContext'\nimport { Match } from './Match'\nimport { SafeFragment } from './SafeFragment'\nimport type {\n StructuralSharingOption,\n ValidateSelected,\n} from './structuralSharing'\nimport type {\n AnyRoute,\n AnyRouter,\n DeepPartial,\n Expand,\n MakeOptionalPathParams,\n MakeOptionalSearchParams,\n MakeRouteMatchUnion,\n MaskOptions,\n MatchRouteOptions,\n RegisteredRouter,\n ResolveRoute,\n ToSubOptionsProps,\n} from '@tanstack/router-core'\n\ndeclare module '@tanstack/router-core' {\n export interface RouteMatchExtensions {\n meta?: Array<React.JSX.IntrinsicElements['meta'] | undefined>\n links?: Array<React.JSX.IntrinsicElements['link'] | undefined>\n scripts?: Array<React.JSX.IntrinsicElements['script'] | undefined>\n styles?: Array<React.JSX.IntrinsicElements['style'] | undefined>\n headScripts?: Array<React.JSX.IntrinsicElements['script'] | undefined>\n }\n}\n\n/**\n * Internal component that renders the router's active match tree with\n * suspense, error, and not-found boundaries. Rendered by `RouterProvider`.\n */\nexport function Matches() {\n const router = useRouter()\n const rootRoute: AnyRoute = router.routesById[rootRouteId]\n\n const PendingComponent =\n rootRoute.options.pendingComponent ?? router.options.defaultPendingComponent\n\n const pendingElement = PendingComponent ? <PendingComponent /> : null\n\n // Do not render a root Suspense during SSR or hydrating from SSR\n const ResolvedSuspense =\n (isServer ?? router.isServer) ||\n (typeof document !== 'undefined' && router.ssr)\n ? SafeFragment\n : React.Suspense\n\n const inner = (\n <ResolvedSuspense fallback={pendingElement}>\n {!(isServer ?? router.isServer) && <Transitioner />}\n <MatchesInner />\n </ResolvedSuspense>\n )\n\n return router.options.InnerWrap ? (\n <router.options.InnerWrap>{inner}</router.options.InnerWrap>\n ) : (\n inner\n )\n}\n\nfunction MatchesInner() {\n const router = useRouter()\n const _isServer = isServer ?? router.isServer\n const matchId = _isServer\n ? router.stores.firstId.get()\n : // eslint-disable-next-line react-hooks/rules-of-hooks\n useStore(router.stores.firstId, (id) => id)\n const resetKey = _isServer\n ? router.stores.loadedAt.get()\n : // eslint-disable-next-line react-hooks/rules-of-hooks\n useStore(router.stores.loadedAt, (loadedAt) => loadedAt)\n\n const matchComponent = matchId ? <Match matchId={matchId} /> : null\n\n return (\n <matchContext.Provider value={matchId}>\n {router.options.disableGlobalCatchBoundary ? (\n matchComponent\n ) : (\n <CatchBoundary\n getResetKey={() => resetKey}\n errorComponent={ErrorComponent}\n onCatch={\n process.env.NODE_ENV !== 'production'\n ? (error) => {\n console.warn(\n `Warning: The following error wasn't caught by any route! At the very least, consider setting an 'errorComponent' in your RootRoute!`,\n )\n console.warn(`Warning: ${error.message || error.toString()}`)\n }\n : undefined\n }\n >\n {matchComponent}\n </CatchBoundary>\n )}\n </matchContext.Provider>\n )\n}\n\nexport type UseMatchRouteOptions<\n TRouter extends AnyRouter = RegisteredRouter,\n TFrom extends string = string,\n TTo extends string | undefined = undefined,\n TMaskFrom extends string = TFrom,\n TMaskTo extends string = '',\n> = ToSubOptionsProps<TRouter, TFrom, TTo> &\n DeepPartial<MakeOptionalSearchParams<TRouter, TFrom, TTo>> &\n DeepPartial<MakeOptionalPathParams<TRouter, TFrom, TTo>> &\n MaskOptions<TRouter, TMaskFrom, TMaskTo> &\n MatchRouteOptions\n\n/**\n * Create a matcher function for testing locations against route definitions.\n *\n * The returned function accepts standard navigation options (`to`, `params`,\n * `search`, etc.) and returns either `false` (no match) or the matched params\n * object when the route matches the current or pending location.\n *\n * Useful for conditional rendering and active UI states.\n *\n * @returns A `matchRoute(options)` function that returns `false` or params.\n * @link https://tanstack.com/router/latest/docs/framework/react/api/router/useMatchRouteHook\n */\nexport function useMatchRoute<TRouter extends AnyRouter = RegisteredRouter>() {\n const router = useRouter()\n\n if (!(isServer ?? router.isServer)) {\n // eslint-disable-next-line react-hooks/rules-of-hooks\n useStore(router.stores.matchRouteDeps, (d) => d)\n }\n\n return React.useCallback(\n <\n const TFrom extends string = string,\n const TTo extends string | undefined = undefined,\n const TMaskFrom extends string = TFrom,\n const TMaskTo extends string = '',\n >(\n opts: UseMatchRouteOptions<TRouter, TFrom, TTo, TMaskFrom, TMaskTo>,\n ):\n | false\n | Expand<ResolveRoute<TRouter, TFrom, TTo>['types']['allParams']> => {\n const { pending, caseSensitive, fuzzy, includeSearch, ...rest } = opts\n\n return router.matchRoute(rest as any, {\n pending,\n caseSensitive,\n fuzzy,\n includeSearch,\n })\n },\n [router],\n )\n}\n\nexport type MakeMatchRouteOptions<\n TRouter extends AnyRouter = RegisteredRouter,\n TFrom extends string = string,\n TTo extends string | undefined = undefined,\n TMaskFrom extends string = TFrom,\n TMaskTo extends string = '',\n> = UseMatchRouteOptions<TRouter, TFrom, TTo, TMaskFrom, TMaskTo> & {\n // If a function is passed as a child, it will be given the `isActive` boolean to aid in further styling on the element it returns\n children?:\n | ((\n params?: Expand<\n ResolveRoute<TRouter, TFrom, TTo>['types']['allParams']\n >,\n ) => React.ReactNode)\n | React.ReactNode\n}\n\n/**\n * Component that conditionally renders its children based on whether a route\n * matches the provided `from`/`to` options. If `children` is a function, it\n * receives the matched params object.\n *\n * @link https://tanstack.com/router/latest/docs/framework/react/api/router/matchRouteComponent\n */\nexport function MatchRoute<\n TRouter extends AnyRouter = RegisteredRouter,\n const TFrom extends string = string,\n const TTo extends string | undefined = undefined,\n const TMaskFrom extends string = TFrom,\n const TMaskTo extends string = '',\n>(props: MakeMatchRouteOptions<TRouter, TFrom, TTo, TMaskFrom, TMaskTo>): any {\n const matchRoute = useMatchRoute()\n const params = matchRoute(props as any) as boolean\n\n if (typeof props.children === 'function') {\n return (props.children as any)(params)\n }\n\n return params ? props.children : null\n}\n\nexport interface UseMatchesBaseOptions<\n TRouter extends AnyRouter,\n TSelected,\n TStructuralSharing,\n> {\n select?: (\n matches: Array<MakeRouteMatchUnion<TRouter>>,\n ) => ValidateSelected<TRouter, TSelected, TStructuralSharing>\n}\n\nexport type UseMatchesResult<\n TRouter extends AnyRouter,\n TSelected,\n> = unknown extends TSelected ? Array<MakeRouteMatchUnion<TRouter>> : TSelected\n\nexport function useMatches<\n TRouter extends AnyRouter = RegisteredRouter,\n TSelected = unknown,\n TStructuralSharing extends boolean = boolean,\n>(\n opts?: UseMatchesBaseOptions<TRouter, TSelected, TStructuralSharing> &\n StructuralSharingOption<TRouter, TSelected, TStructuralSharing>,\n): UseMatchesResult<TRouter, TSelected> {\n const router = useRouter<TRouter>()\n const previousResult =\n React.useRef<ValidateSelected<TRouter, TSelected, TStructuralSharing>>(\n undefined,\n )\n\n if (isServer ?? router.isServer) {\n const matches = router.stores.matches.get() as Array<\n MakeRouteMatchUnion<TRouter>\n >\n return (opts?.select ? opts.select(matches) : matches) as UseMatchesResult<\n TRouter,\n TSelected\n >\n }\n\n // eslint-disable-next-line react-hooks/rules-of-hooks\n return useStore(router.stores.matches, (matches) => {\n const selected = opts?.select\n ? opts.select(matches as Array<MakeRouteMatchUnion<TRouter>>)\n : (matches as any)\n\n if (opts?.structuralSharing ?? router.options.defaultStructuralSharing) {\n const shared = replaceEqualDeep(previousResult.current, selected)\n previousResult.current = shared\n return shared\n }\n\n return selected\n }) as UseMatchesResult<TRouter, TSelected>\n}\n\n/**\n * Read the full array of active route matches or select a derived subset.\n *\n * Useful for debugging, breadcrumbs, or aggregating metadata across matches.\n *\n * @returns The array of matches (or the selected value).\n * @link https://tanstack.com/router/latest/docs/framework/react/api/router/useMatchesHook\n */\n\n/**\n * Read the full array of active route matches or select a derived subset.\n *\n * Useful for debugging, breadcrumbs, or aggregating metadata across matches.\n *\n * @link https://tanstack.com/router/latest/docs/framework/react/api/router/useMatchesHook\n */\nexport function useParentMatches<\n TRouter extends AnyRouter = RegisteredRouter,\n TSelected = unknown,\n TStructuralSharing extends boolean = boolean,\n>(\n opts?: UseMatchesBaseOptions<TRouter, TSelected, TStructuralSharing> &\n StructuralSharingOption<TRouter, TSelected, TStructuralSharing>,\n): UseMatchesResult<TRouter, TSelected> {\n const contextMatchId = React.useContext(matchContext)\n\n return useMatches({\n select: (matches: Array<MakeRouteMatchUnion<TRouter>>) => {\n matches = matches.slice(\n 0,\n matches.findIndex((d) => d.id === contextMatchId),\n )\n return opts?.select ? opts.select(matches) : matches\n },\n structuralSharing: opts?.structuralSharing,\n } as any)\n}\n\n/**\n * Read the array of active route matches that are children of the current\n * match (or selected parent) in the match tree.\n */\nexport function useChildMatches<\n TRouter extends AnyRouter = RegisteredRouter,\n TSelected = unknown,\n TStructuralSharing extends boolean = boolean,\n>(\n opts?: UseMatchesBaseOptions<TRouter, TSelected, TStructuralSharing> &\n StructuralSharingOption<TRouter, TSelected, TStructuralSharing>,\n): UseMatchesResult<TRouter, TSelected> {\n const contextMatchId = React.useContext(matchContext)\n\n return useMatches({\n select: (matches: Array<MakeRouteMatchUnion<TRouter>>) => {\n matches = matches.slice(\n matches.findIndex((d) => d.id === contextMatchId) + 1,\n )\n return opts?.select ? opts.select(matches) : matches\n },\n structuralSharing: opts?.structuralSharing,\n } as any)\n}\n"],"mappings":"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"} | ||
| {"version":3,"file":"Matches.cjs","names":[],"sources":["../../src/Matches.tsx"],"sourcesContent":["'use client'\n\nimport * as React from 'react'\nimport { useStore } from '@tanstack/react-store'\nimport { rootRouteId } from '@tanstack/router-core'\nimport { isServer } from '@tanstack/router-core/isServer'\nimport { CatchBoundary, ErrorComponent } from './CatchBoundary'\nimport { useRouter } from './useRouter'\nimport { useStructuralSharing } from './useMatch'\nimport { Transitioner } from './Transitioner'\nimport { matchContext } from './matchContext'\nimport { Match } from './Match'\nimport { SafeFragment } from './SafeFragment'\nimport type {\n StructuralSharingOption,\n ValidateSelected,\n} from './structuralSharing'\nimport type {\n AnyRoute,\n AnyRouter,\n DeepPartial,\n Expand,\n MakeOptionalPathParams,\n MakeOptionalSearchParams,\n MakeRouteMatchUnion,\n MaskOptions,\n MatchRouteOptions,\n RegisteredRouter,\n ResolveRoute,\n ToSubOptionsProps,\n} from '@tanstack/router-core'\n\ndeclare module '@tanstack/router-core' {\n export interface RouteMatchExtensions {\n meta?: Array<React.JSX.IntrinsicElements['meta'] | undefined>\n links?: Array<React.JSX.IntrinsicElements['link'] | undefined>\n scripts?: Array<React.JSX.IntrinsicElements['script'] | undefined>\n styles?: Array<React.JSX.IntrinsicElements['style'] | undefined>\n headScripts?: Array<React.JSX.IntrinsicElements['script'] | undefined>\n }\n}\n\n/**\n * Internal component that renders the router's active match tree with\n * suspense, error, and not-found boundaries. Rendered by `RouterProvider`.\n */\nexport function Matches() {\n const router = useRouter()\n const rootRoute: AnyRoute = router.routesById[rootRouteId]\n\n const PendingComponent =\n rootRoute.options.pendingComponent ?? router.options.defaultPendingComponent\n\n const pendingElement = PendingComponent ? <PendingComponent /> : null\n\n // Do not render a root Suspense during SSR or hydrating from SSR\n const ResolvedSuspense =\n (isServer ?? router.isServer) ||\n (typeof document !== 'undefined' && router.ssr)\n ? SafeFragment\n : React.Suspense\n\n const inner = (\n <ResolvedSuspense fallback={pendingElement}>\n {!(isServer ?? router.isServer) && <Transitioner />}\n <MatchesInner />\n </ResolvedSuspense>\n )\n\n return router.options.InnerWrap ? (\n <router.options.InnerWrap>{inner}</router.options.InnerWrap>\n ) : (\n inner\n )\n}\n\nfunction MatchesInner() {\n const router = useRouter()\n const _isServer = isServer ?? router.isServer\n const matchId = _isServer\n ? router.stores.firstId.get()\n : // eslint-disable-next-line react-hooks/rules-of-hooks\n useStore(router.stores.firstId, (id) => id)\n const resetKey = _isServer\n ? router.stores.loadedAt.get()\n : // eslint-disable-next-line react-hooks/rules-of-hooks\n useStore(router.stores.loadedAt, (loadedAt) => loadedAt)\n\n const matchComponent = matchId ? <Match matchId={matchId} /> : null\n\n return (\n <matchContext.Provider value={matchId}>\n {router.options.disableGlobalCatchBoundary ? (\n matchComponent\n ) : (\n <CatchBoundary\n getResetKey={() => resetKey}\n errorComponent={ErrorComponent}\n onCatch={\n process.env.NODE_ENV !== 'production'\n ? (error) => {\n console.warn(\n `Warning: The following error wasn't caught by any route! At the very least, consider setting an 'errorComponent' in your RootRoute!`,\n )\n console.warn(`Warning: ${error.message || error.toString()}`)\n }\n : undefined\n }\n >\n {matchComponent}\n </CatchBoundary>\n )}\n </matchContext.Provider>\n )\n}\n\nexport type UseMatchRouteOptions<\n TRouter extends AnyRouter = RegisteredRouter,\n TFrom extends string = string,\n TTo extends string | undefined = undefined,\n TMaskFrom extends string = TFrom,\n TMaskTo extends string = '',\n> = ToSubOptionsProps<TRouter, TFrom, TTo> &\n DeepPartial<MakeOptionalSearchParams<TRouter, TFrom, TTo>> &\n DeepPartial<MakeOptionalPathParams<TRouter, TFrom, TTo>> &\n MaskOptions<TRouter, TMaskFrom, TMaskTo> &\n MatchRouteOptions\n\n/**\n * Create a matcher function for testing locations against route definitions.\n *\n * The returned function accepts standard navigation options (`to`, `params`,\n * `search`, etc.) and returns either `false` (no match) or the matched params\n * object when the route matches the current or pending location.\n *\n * Useful for conditional rendering and active UI states.\n *\n * @returns A `matchRoute(options)` function that returns `false` or params.\n * @link https://tanstack.com/router/latest/docs/framework/react/api/router/useMatchRouteHook\n */\nexport function useMatchRoute<TRouter extends AnyRouter = RegisteredRouter>() {\n const router = useRouter()\n\n if (!(isServer ?? router.isServer)) {\n // eslint-disable-next-line react-hooks/rules-of-hooks\n useStore(router.stores.matchRouteDeps, (d) => d)\n }\n\n return React.useCallback(\n <\n const TFrom extends string = string,\n const TTo extends string | undefined = undefined,\n const TMaskFrom extends string = TFrom,\n const TMaskTo extends string = '',\n >(\n opts: UseMatchRouteOptions<TRouter, TFrom, TTo, TMaskFrom, TMaskTo>,\n ):\n | false\n | Expand<ResolveRoute<TRouter, TFrom, TTo>['types']['allParams']> => {\n const { pending, caseSensitive, fuzzy, includeSearch, ...rest } = opts\n\n return router.matchRoute(rest as any, {\n pending,\n caseSensitive,\n fuzzy,\n includeSearch,\n })\n },\n [router],\n )\n}\n\nexport type MakeMatchRouteOptions<\n TRouter extends AnyRouter = RegisteredRouter,\n TFrom extends string = string,\n TTo extends string | undefined = undefined,\n TMaskFrom extends string = TFrom,\n TMaskTo extends string = '',\n> = UseMatchRouteOptions<TRouter, TFrom, TTo, TMaskFrom, TMaskTo> & {\n // If a function is passed as a child, it will be given the `isActive` boolean to aid in further styling on the element it returns\n children?:\n | ((\n params?: Expand<\n ResolveRoute<TRouter, TFrom, TTo>['types']['allParams']\n >,\n ) => React.ReactNode)\n | React.ReactNode\n}\n\n/**\n * Component that conditionally renders its children based on whether a route\n * matches the provided `from`/`to` options. If `children` is a function, it\n * receives the matched params object.\n *\n * @link https://tanstack.com/router/latest/docs/framework/react/api/router/matchRouteComponent\n */\nexport function MatchRoute<\n TRouter extends AnyRouter = RegisteredRouter,\n const TFrom extends string = string,\n const TTo extends string | undefined = undefined,\n const TMaskFrom extends string = TFrom,\n const TMaskTo extends string = '',\n>(props: MakeMatchRouteOptions<TRouter, TFrom, TTo, TMaskFrom, TMaskTo>): any {\n const matchRoute = useMatchRoute()\n const params = matchRoute(props as any) as boolean\n\n if (typeof props.children === 'function') {\n return (props.children as any)(params)\n }\n\n return params ? props.children : null\n}\n\nexport interface UseMatchesBaseOptions<\n TRouter extends AnyRouter,\n TSelected,\n TStructuralSharing,\n> {\n select?: (\n matches: Array<MakeRouteMatchUnion<TRouter>>,\n ) => ValidateSelected<TRouter, TSelected, TStructuralSharing>\n}\n\nexport type UseMatchesResult<\n TRouter extends AnyRouter,\n TSelected,\n> = unknown extends TSelected ? Array<MakeRouteMatchUnion<TRouter>> : TSelected\n\nexport function useMatches<\n TRouter extends AnyRouter = RegisteredRouter,\n TSelected = unknown,\n TStructuralSharing extends boolean = boolean,\n>(\n opts?: UseMatchesBaseOptions<TRouter, TSelected, TStructuralSharing> &\n StructuralSharingOption<TRouter, TSelected, TStructuralSharing>,\n): UseMatchesResult<TRouter, TSelected> {\n const router = useRouter<TRouter>()\n\n if (isServer ?? router.isServer) {\n const matches = router.stores.matches.get() as Array<\n MakeRouteMatchUnion<TRouter>\n >\n return (opts?.select ? opts.select(matches) : matches) as UseMatchesResult<\n TRouter,\n TSelected\n >\n }\n\n // eslint-disable-next-line react-hooks/rules-of-hooks -- condition is static\n return useStore(\n router.stores.matches,\n // eslint-disable-next-line react-hooks/rules-of-hooks -- condition is static\n useStructuralSharing(opts, router),\n ) as UseMatchesResult<TRouter, TSelected>\n}\n\n/**\n * Read the full array of active route matches or select a derived subset.\n *\n * Useful for debugging, breadcrumbs, or aggregating metadata across matches.\n *\n * @returns The array of matches (or the selected value).\n * @link https://tanstack.com/router/latest/docs/framework/react/api/router/useMatchesHook\n */\n\n/**\n * Read the full array of active route matches or select a derived subset.\n *\n * Useful for debugging, breadcrumbs, or aggregating metadata across matches.\n *\n * @link https://tanstack.com/router/latest/docs/framework/react/api/router/useMatchesHook\n */\nexport function useParentMatches<\n TRouter extends AnyRouter = RegisteredRouter,\n TSelected = unknown,\n TStructuralSharing extends boolean = boolean,\n>(\n opts?: UseMatchesBaseOptions<TRouter, TSelected, TStructuralSharing> &\n StructuralSharingOption<TRouter, TSelected, TStructuralSharing>,\n): UseMatchesResult<TRouter, TSelected> {\n const contextMatchId = React.useContext(matchContext)\n\n return useMatches({\n select: (matches: Array<MakeRouteMatchUnion<TRouter>>) => {\n matches = matches.slice(\n 0,\n matches.findIndex((d) => d.id === contextMatchId),\n )\n return opts?.select ? opts.select(matches) : matches\n },\n structuralSharing: opts?.structuralSharing,\n } as any)\n}\n\n/**\n * Read the array of active route matches that are children of the current\n * match (or selected parent) in the match tree.\n */\nexport function useChildMatches<\n TRouter extends AnyRouter = RegisteredRouter,\n TSelected = unknown,\n TStructuralSharing extends boolean = boolean,\n>(\n opts?: UseMatchesBaseOptions<TRouter, TSelected, TStructuralSharing> &\n StructuralSharingOption<TRouter, TSelected, TStructuralSharing>,\n): UseMatchesResult<TRouter, TSelected> {\n const contextMatchId = React.useContext(matchContext)\n\n return useMatches({\n select: (matches: Array<MakeRouteMatchUnion<TRouter>>) => {\n matches = matches.slice(\n matches.findIndex((d) => d.id === contextMatchId) + 1,\n )\n return opts?.select ? opts.select(matches) : matches\n },\n structuralSharing: opts?.structuralSharing,\n } as any)\n}\n"],"mappings":"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"} |
@@ -22,2 +22,3 @@ const require_runtime = require("../_virtual/_rolldown/runtime.cjs"); | ||
| } | ||
| var isAbortError = (request, error) => request.signal.aborted && error === request.signal.reason || error instanceof Error && error.name === "AbortError"; | ||
| var renderRouterToStream = async ({ request, router, responseHeaders, children }) => { | ||
@@ -28,3 +29,6 @@ if (typeof react_dom_server.default.renderToReadableStream === "function") { | ||
| nonce: router.options.ssr?.nonce, | ||
| progressiveChunkSize: Number.POSITIVE_INFINITY | ||
| progressiveChunkSize: Number.POSITIVE_INFINITY, | ||
| onError: (error, info) => { | ||
| if (!isAbortError(request, error)) console.error("Error in renderToReadableStream:", error, info); | ||
| } | ||
| }); | ||
@@ -81,3 +85,3 @@ if ((0, isbot.isbot)(request.headers.get("User-Agent"))) await waitForReadyOrAbort(stream.allReady, request.signal); | ||
| onError: (error, info) => { | ||
| console.error("Error in renderToPipeableStream:", error, info); | ||
| if (!isAbortError(request, error)) console.error("Error in renderToPipeableStream:", error, info); | ||
| abortPipeable(error, { defaultError: true }); | ||
@@ -84,0 +88,0 @@ } |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"renderRouterToStream.cjs","names":[],"sources":["../../../src/ssr/renderRouterToStream.tsx"],"sourcesContent":["import { PassThrough } from 'node:stream'\nimport ReactDOMServer from 'react-dom/server'\nimport { isbot } from 'isbot'\nimport {\n createSsrStreamResponse,\n transformPipeableStreamWithRouter,\n transformReadableStreamWithRouter,\n} from '@tanstack/router-core/ssr/server'\nimport type { AnyRouter } from '@tanstack/router-core'\nimport type { ReadableStream } from 'node:stream/web'\nimport type { ReactNode } from 'react'\n\nconst noop = () => {}\n\n// Bot responses wait for `allReady` so crawlers receive complete HTML.\n// If the request disconnects during that wait, React may not settle quickly;\n// unblock the wait so the response pipeline can abort and clean up.\nasync function waitForReadyOrAbort(\n ready: Promise<unknown>,\n signal: AbortSignal,\n) {\n let cleanup = noop\n try {\n await Promise.race([\n ready,\n new Promise<void>((resolve) => {\n const onAbort = () => resolve()\n cleanup = () => signal.removeEventListener('abort', onAbort)\n signal.addEventListener('abort', onAbort, { once: true })\n if (signal.aborted) resolve()\n }),\n ])\n } finally {\n cleanup()\n }\n}\n\nexport const renderRouterToStream = async ({\n request,\n router,\n responseHeaders,\n children,\n}: {\n request: Request\n router: AnyRouter\n responseHeaders: Headers\n children: ReactNode\n}) => {\n if (typeof ReactDOMServer.renderToReadableStream === 'function') {\n const stream = await ReactDOMServer.renderToReadableStream(children, {\n signal: request.signal,\n nonce: router.options.ssr?.nonce,\n progressiveChunkSize: Number.POSITIVE_INFINITY,\n })\n\n if (isbot(request.headers.get('User-Agent'))) {\n await waitForReadyOrAbort(stream.allReady, request.signal)\n }\n\n const responseStream = transformReadableStreamWithRouter(\n router,\n stream as unknown as ReadableStream,\n { onAbort: () => stream.cancel().catch(() => {}) },\n )\n return createSsrStreamResponse(\n router,\n new Response(responseStream as any, {\n status: router.stores.statusCode.get(),\n headers: responseHeaders,\n }),\n )\n }\n\n if (typeof ReactDOMServer.renderToPipeableStream === 'function') {\n const reactAppPassthrough = new PassThrough()\n\n let pipeable:\n | ReturnType<typeof ReactDOMServer.renderToPipeableStream>\n | undefined\n let responseAttached = false\n let aborted = false\n let endedBeforeAttach = false\n let pendingAbortReason: unknown\n const toError = (reason: unknown) =>\n reason instanceof Error\n ? reason\n : new Error(String(reason ?? 'SSR aborted'))\n const destroyError = (reason: unknown) =>\n reason === undefined ? undefined : toError(reason)\n const pendingDestroyError = () =>\n pendingAbortReason === undefined\n ? toError(pendingAbortReason)\n : destroyError(pendingAbortReason)\n const finishPassThrough = (\n reason: unknown,\n opts?: { defaultError?: boolean },\n ) => {\n if (reactAppPassthrough.destroyed) return\n if (responseAttached) {\n reactAppPassthrough.destroy(\n opts?.defaultError ? toError(reason) : destroyError(reason),\n )\n } else {\n endedBeforeAttach = true\n // onError can fire synchronously before React returns the pipeable\n // handle and before Readable.toWeb() is attached. Defer touching the\n // PassThrough until after the router transform can observe the error.\n }\n }\n const abortPipeable = (\n reason?: unknown,\n opts?: { defaultError?: boolean },\n ) => {\n if (aborted) return\n aborted = true\n pendingAbortReason = reason\n const err = toError(reason)\n try {\n pipeable?.abort(err)\n } catch {\n // ignore — React may throw if already aborted/finished\n }\n finishPassThrough(reason, opts)\n }\n\n // Register before attaching the router transform; the transform may\n // synchronously cleanup/error, and cleanup must still remove this listener.\n if (request.signal.aborted) {\n abortPipeable(request.signal.reason)\n } else {\n const onRequestAbort = () => abortPipeable(request.signal.reason)\n request.signal.addEventListener('abort', onRequestAbort, { once: true })\n router.serverSsr?.onCleanup(() => {\n request.signal.removeEventListener('abort', onRequestAbort)\n })\n }\n\n try {\n pipeable = ReactDOMServer.renderToPipeableStream(children, {\n nonce: router.options.ssr?.nonce,\n progressiveChunkSize: Number.POSITIVE_INFINITY,\n ...(isbot(request.headers.get('User-Agent'))\n ? {\n onAllReady() {\n pipeable!.pipe(reactAppPassthrough)\n },\n }\n : {\n onShellReady() {\n pipeable!.pipe(reactAppPassthrough)\n },\n }),\n onError: (error, info) => {\n console.error('Error in renderToPipeableStream:', error, info)\n abortPipeable(error, { defaultError: true })\n },\n })\n } catch (e) {\n console.error('Error in renderToPipeableStream:', e)\n router.serverSsr?.cleanup()\n throw e\n }\n\n const responseStream = transformPipeableStreamWithRouter(\n router,\n reactAppPassthrough,\n { onAbort: abortPipeable },\n )\n responseAttached = true\n\n if (endedBeforeAttach) {\n reactAppPassthrough.destroy(pendingDestroyError())\n }\n\n // React's onError may have fired synchronously inside\n // renderToPipeableStream before `pipeable` was assigned. If so,\n // abortPipeable ran without a pipeable handle; re-apply the abort now.\n if (aborted && pipeable) {\n try {\n pipeable.abort(toError(pendingAbortReason))\n } catch {\n // ignore — React may throw if already aborted/finished\n }\n }\n\n return createSsrStreamResponse(\n router,\n new Response(responseStream as any, {\n status: router.stores.statusCode.get(),\n headers: responseHeaders,\n }),\n )\n }\n\n throw new Error(\n 'No renderToReadableStream or renderToPipeableStream found in react-dom/server. Ensure you are using a version of react-dom that supports streaming.',\n )\n}\n"],"mappings":"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"} | ||
| {"version":3,"file":"renderRouterToStream.cjs","names":[],"sources":["../../../src/ssr/renderRouterToStream.tsx"],"sourcesContent":["import { PassThrough } from 'node:stream'\nimport ReactDOMServer from 'react-dom/server'\nimport { isbot } from 'isbot'\nimport {\n createSsrStreamResponse,\n transformPipeableStreamWithRouter,\n transformReadableStreamWithRouter,\n} from '@tanstack/router-core/ssr/server'\nimport type { AnyRouter } from '@tanstack/router-core'\nimport type { ReadableStream } from 'node:stream/web'\nimport type { ReactNode } from 'react'\n\nconst noop = () => {}\n\n// Bot responses wait for `allReady` so crawlers receive complete HTML.\n// If the request disconnects during that wait, React may not settle quickly;\n// unblock the wait so the response pipeline can abort and clean up.\nasync function waitForReadyOrAbort(\n ready: Promise<unknown>,\n signal: AbortSignal,\n) {\n let cleanup = noop\n try {\n await Promise.race([\n ready,\n new Promise<void>((resolve) => {\n const onAbort = () => resolve()\n cleanup = () => signal.removeEventListener('abort', onAbort)\n signal.addEventListener('abort', onAbort, { once: true })\n if (signal.aborted) resolve()\n }),\n ])\n } finally {\n cleanup()\n }\n}\n\n// A client disconnecting mid-stream is normal operation, not a render\n// failure; don't let React's onError log it as one.\nconst isAbortError = (request: Request, error: unknown) =>\n (request.signal.aborted && error === request.signal.reason) ||\n (error instanceof Error && error.name === 'AbortError')\n\nexport const renderRouterToStream = async ({\n request,\n router,\n responseHeaders,\n children,\n}: {\n request: Request\n router: AnyRouter\n responseHeaders: Headers\n children: ReactNode\n}) => {\n if (typeof ReactDOMServer.renderToReadableStream === 'function') {\n const stream = await ReactDOMServer.renderToReadableStream(children, {\n signal: request.signal,\n nonce: router.options.ssr?.nonce,\n progressiveChunkSize: Number.POSITIVE_INFINITY,\n onError: (error, info) => {\n if (!isAbortError(request, error)) {\n console.error('Error in renderToReadableStream:', error, info)\n }\n },\n })\n\n if (isbot(request.headers.get('User-Agent'))) {\n await waitForReadyOrAbort(stream.allReady, request.signal)\n }\n\n const responseStream = transformReadableStreamWithRouter(\n router,\n stream as unknown as ReadableStream,\n { onAbort: () => stream.cancel().catch(() => {}) },\n )\n return createSsrStreamResponse(\n router,\n new Response(responseStream as any, {\n status: router.stores.statusCode.get(),\n headers: responseHeaders,\n }),\n )\n }\n\n if (typeof ReactDOMServer.renderToPipeableStream === 'function') {\n const reactAppPassthrough = new PassThrough()\n\n let pipeable:\n | ReturnType<typeof ReactDOMServer.renderToPipeableStream>\n | undefined\n let responseAttached = false\n let aborted = false\n let endedBeforeAttach = false\n let pendingAbortReason: unknown\n const toError = (reason: unknown) =>\n reason instanceof Error\n ? reason\n : new Error(String(reason ?? 'SSR aborted'))\n const destroyError = (reason: unknown) =>\n reason === undefined ? undefined : toError(reason)\n const pendingDestroyError = () =>\n pendingAbortReason === undefined\n ? toError(pendingAbortReason)\n : destroyError(pendingAbortReason)\n const finishPassThrough = (\n reason: unknown,\n opts?: { defaultError?: boolean },\n ) => {\n if (reactAppPassthrough.destroyed) return\n if (responseAttached) {\n reactAppPassthrough.destroy(\n opts?.defaultError ? toError(reason) : destroyError(reason),\n )\n } else {\n endedBeforeAttach = true\n // onError can fire synchronously before React returns the pipeable\n // handle and before Readable.toWeb() is attached. Defer touching the\n // PassThrough until after the router transform can observe the error.\n }\n }\n const abortPipeable = (\n reason?: unknown,\n opts?: { defaultError?: boolean },\n ) => {\n if (aborted) return\n aborted = true\n pendingAbortReason = reason\n const err = toError(reason)\n try {\n pipeable?.abort(err)\n } catch {\n // ignore — React may throw if already aborted/finished\n }\n finishPassThrough(reason, opts)\n }\n\n // Register before attaching the router transform; the transform may\n // synchronously cleanup/error, and cleanup must still remove this listener.\n if (request.signal.aborted) {\n abortPipeable(request.signal.reason)\n } else {\n const onRequestAbort = () => abortPipeable(request.signal.reason)\n request.signal.addEventListener('abort', onRequestAbort, { once: true })\n router.serverSsr?.onCleanup(() => {\n request.signal.removeEventListener('abort', onRequestAbort)\n })\n }\n\n try {\n pipeable = ReactDOMServer.renderToPipeableStream(children, {\n nonce: router.options.ssr?.nonce,\n progressiveChunkSize: Number.POSITIVE_INFINITY,\n ...(isbot(request.headers.get('User-Agent'))\n ? {\n onAllReady() {\n pipeable!.pipe(reactAppPassthrough)\n },\n }\n : {\n onShellReady() {\n pipeable!.pipe(reactAppPassthrough)\n },\n }),\n onError: (error, info) => {\n if (!isAbortError(request, error)) {\n console.error('Error in renderToPipeableStream:', error, info)\n }\n abortPipeable(error, { defaultError: true })\n },\n })\n } catch (e) {\n console.error('Error in renderToPipeableStream:', e)\n router.serverSsr?.cleanup()\n throw e\n }\n\n const responseStream = transformPipeableStreamWithRouter(\n router,\n reactAppPassthrough,\n { onAbort: abortPipeable },\n )\n responseAttached = true\n\n if (endedBeforeAttach) {\n reactAppPassthrough.destroy(pendingDestroyError())\n }\n\n // React's onError may have fired synchronously inside\n // renderToPipeableStream before `pipeable` was assigned. If so,\n // abortPipeable ran without a pipeable handle; re-apply the abort now.\n if (aborted && pipeable) {\n try {\n pipeable.abort(toError(pendingAbortReason))\n } catch {\n // ignore — React may throw if already aborted/finished\n }\n }\n\n return createSsrStreamResponse(\n router,\n new Response(responseStream as any, {\n status: router.stores.statusCode.get(),\n headers: responseHeaders,\n }),\n )\n }\n\n throw new Error(\n 'No renderToReadableStream or renderToPipeableStream found in react-dom/server. Ensure you are using a version of react-dom that supports streaming.',\n )\n}\n"],"mappings":"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"} |
| "use client"; | ||
| const require_useRouter = require("./useRouter.cjs"); | ||
| let _tanstack_router_core = require("@tanstack/router-core"); | ||
| let react = require("react"); | ||
| const require_useMatch = require("./useMatch.cjs"); | ||
| let _tanstack_react_store = require("@tanstack/react-store"); | ||
@@ -25,12 +24,3 @@ let _tanstack_router_core_isServer = require("@tanstack/router-core/isServer"); | ||
| } | ||
| const previousResult = (0, react.useRef)(void 0); | ||
| return (0, _tanstack_react_store.useStore)(router.stores.location, (location) => { | ||
| const selected = opts?.select ? opts.select(location) : location; | ||
| if (opts?.structuralSharing ?? router.options.defaultStructuralSharing) { | ||
| const shared = (0, _tanstack_router_core.replaceEqualDeep)(previousResult.current, selected); | ||
| previousResult.current = shared; | ||
| return shared; | ||
| } | ||
| return selected; | ||
| }); | ||
| return (0, _tanstack_react_store.useStore)(router.stores.location, require_useMatch.useStructuralSharing(opts, router)); | ||
| } | ||
@@ -37,0 +27,0 @@ //#endregion |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"useLocation.cjs","names":[],"sources":["../../src/useLocation.tsx"],"sourcesContent":["'use client'\n\nimport { useStore } from '@tanstack/react-store'\nimport { useRef } from 'react'\nimport { replaceEqualDeep } from '@tanstack/router-core'\nimport { isServer } from '@tanstack/router-core/isServer'\nimport { useRouter } from './useRouter'\nimport type {\n StructuralSharingOption,\n ValidateSelected,\n} from './structuralSharing'\nimport type {\n AnyRouter,\n RegisteredRouter,\n RouterState,\n} from '@tanstack/router-core'\n\nexport interface UseLocationBaseOptions<\n TRouter extends AnyRouter,\n TSelected,\n TStructuralSharing extends boolean = boolean,\n> {\n select?: (\n state: RouterState<TRouter['routeTree']>['location'],\n ) => ValidateSelected<TRouter, TSelected, TStructuralSharing>\n}\n\nexport type UseLocationResult<\n TRouter extends AnyRouter,\n TSelected,\n> = unknown extends TSelected\n ? RouterState<TRouter['routeTree']>['location']\n : TSelected\n\n/**\n * Read the current location from the router state with optional selection.\n * Useful for subscribing to just the pieces of location you care about.\n *\n * Options:\n * - `select`: Project the `location` object to a derived value\n * - `structuralSharing`: Enable structural sharing for stable references\n *\n * @returns The current location (or selected value).\n * @link https://tanstack.com/router/latest/docs/framework/react/api/router/useLocationHook\n */\nexport function useLocation<\n TRouter extends AnyRouter = RegisteredRouter,\n TSelected = unknown,\n TStructuralSharing extends boolean = boolean,\n>(\n opts?: UseLocationBaseOptions<TRouter, TSelected, TStructuralSharing> &\n StructuralSharingOption<TRouter, TSelected, TStructuralSharing>,\n): UseLocationResult<TRouter, TSelected> {\n const router = useRouter<TRouter>()\n\n if (isServer ?? router.isServer) {\n const location = router.stores.location.get()\n return (\n opts?.select ? opts.select(location as any) : location\n ) as UseLocationResult<TRouter, TSelected>\n }\n\n const previousResult =\n // eslint-disable-next-line react-hooks/rules-of-hooks -- condition is static\n useRef<ValidateSelected<TRouter, TSelected, TStructuralSharing>>(undefined)\n\n // eslint-disable-next-line react-hooks/rules-of-hooks -- condition is static\n return useStore(router.stores.location, (location) => {\n const selected = (\n opts?.select ? opts.select(location as any) : location\n ) as ValidateSelected<TRouter, TSelected, TStructuralSharing>\n\n if (opts?.structuralSharing ?? router.options.defaultStructuralSharing) {\n const shared = replaceEqualDeep(previousResult.current, selected)\n previousResult.current = shared\n return shared\n }\n\n return selected\n }) as UseLocationResult<TRouter, TSelected>\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AA6CA,SAAgB,YAKd,MAEuC;CACvC,MAAM,SAAS,kBAAA,UAAmB;CAElC,IAAI,+BAAA,YAAY,OAAO,UAAU;EAC/B,MAAM,WAAW,OAAO,OAAO,SAAS,IAAI;EAC5C,OACE,MAAM,SAAS,KAAK,OAAO,QAAe,IAAI;CAElD;CAEA,MAAM,kBAAA,GAAA,MAAA,QAE6D,KAAA,CAAS;CAG5E,QAAA,GAAA,sBAAA,UAAgB,OAAO,OAAO,WAAW,aAAa;EACpD,MAAM,WACJ,MAAM,SAAS,KAAK,OAAO,QAAe,IAAI;EAGhD,IAAI,MAAM,qBAAqB,OAAO,QAAQ,0BAA0B;GACtE,MAAM,UAAA,GAAA,sBAAA,kBAA0B,eAAe,SAAS,QAAQ;GAChE,eAAe,UAAU;GACzB,OAAO;EACT;EAEA,OAAO;CACT,CAAC;AACH"} | ||
| {"version":3,"file":"useLocation.cjs","names":[],"sources":["../../src/useLocation.tsx"],"sourcesContent":["'use client'\n\nimport { useStore } from '@tanstack/react-store'\nimport { isServer } from '@tanstack/router-core/isServer'\nimport { useRouter } from './useRouter'\nimport { useStructuralSharing } from './useMatch'\nimport type {\n StructuralSharingOption,\n ValidateSelected,\n} from './structuralSharing'\nimport type {\n AnyRouter,\n RegisteredRouter,\n RouterState,\n} from '@tanstack/router-core'\n\nexport interface UseLocationBaseOptions<\n TRouter extends AnyRouter,\n TSelected,\n TStructuralSharing extends boolean = boolean,\n> {\n select?: (\n state: RouterState<TRouter['routeTree']>['location'],\n ) => ValidateSelected<TRouter, TSelected, TStructuralSharing>\n}\n\nexport type UseLocationResult<\n TRouter extends AnyRouter,\n TSelected,\n> = unknown extends TSelected\n ? RouterState<TRouter['routeTree']>['location']\n : TSelected\n\n/**\n * Read the current location from the router state with optional selection.\n * Useful for subscribing to just the pieces of location you care about.\n *\n * Options:\n * - `select`: Project the `location` object to a derived value\n * - `structuralSharing`: Enable structural sharing for stable references\n *\n * @returns The current location (or selected value).\n * @link https://tanstack.com/router/latest/docs/framework/react/api/router/useLocationHook\n */\nexport function useLocation<\n TRouter extends AnyRouter = RegisteredRouter,\n TSelected = unknown,\n TStructuralSharing extends boolean = boolean,\n>(\n opts?: UseLocationBaseOptions<TRouter, TSelected, TStructuralSharing> &\n StructuralSharingOption<TRouter, TSelected, TStructuralSharing>,\n): UseLocationResult<TRouter, TSelected> {\n const router = useRouter<TRouter>()\n\n if (isServer ?? router.isServer) {\n const location = router.stores.location.get()\n return (\n opts?.select ? opts.select(location as any) : location\n ) as UseLocationResult<TRouter, TSelected>\n }\n\n // eslint-disable-next-line react-hooks/rules-of-hooks -- condition is static\n return useStore(\n router.stores.location,\n // eslint-disable-next-line react-hooks/rules-of-hooks -- condition is static\n useStructuralSharing(opts, router),\n ) as UseLocationResult<TRouter, TSelected>\n}\n"],"mappings":";;;;;;;;;;;;;;;;;AA4CA,SAAgB,YAKd,MAEuC;CACvC,MAAM,SAAS,kBAAA,UAAmB;CAElC,IAAI,+BAAA,YAAY,OAAO,UAAU;EAC/B,MAAM,WAAW,OAAO,OAAO,SAAS,IAAI;EAC5C,OACE,MAAM,SAAS,KAAK,OAAO,QAAe,IAAI;CAElD;CAGA,QAAA,GAAA,sBAAA,UACE,OAAO,OAAO,UAEd,iBAAA,qBAAqB,MAAM,MAAM,CACnC;AACF"} |
+27
-23
@@ -12,5 +12,15 @@ "use client"; | ||
| var dummyStore = { | ||
| get: () => void 0, | ||
| subscribe: () => ({ unsubscribe: () => {} }) | ||
| get() {}, | ||
| subscribe() { | ||
| return { unsubscribe() {} }; | ||
| } | ||
| }; | ||
| function useStructuralSharing(opts, router) { | ||
| const previousResult = react.useRef(); | ||
| return (slice) => { | ||
| const selected = opts?.select ? opts.select(slice) : slice; | ||
| if (opts?.structuralSharing ?? router.options.defaultStructuralSharing) return previousResult.current = (0, _tanstack_router_core.replaceEqualDeep)(previousResult.current, selected); | ||
| return selected; | ||
| }; | ||
| } | ||
| /** | ||
@@ -23,32 +33,26 @@ * Read and select the nearest or targeted route match. | ||
| const nearestMatchId = react.useContext(opts.from ? require_matchContext.dummyMatchContext : require_matchContext.matchContext); | ||
| const key = opts.from ?? nearestMatchId; | ||
| const matchStore = key ? opts.from ? router.stores.getRouteMatchStore(key) : router.stores.matchStores.get(key) : void 0; | ||
| const matchStore = opts.from ? router.stores.getRouteMatchStore(opts.from) : router.stores.matchStores.get(nearestMatchId); | ||
| if (_tanstack_router_core_isServer.isServer ?? router.isServer) { | ||
| const match = matchStore?.get(); | ||
| if ((opts.shouldThrow ?? true) && !match) { | ||
| if (process.env.NODE_ENV !== "production") throw new Error(`Invariant failed: Could not find ${opts.from ? `an active match from "${opts.from}"` : "a nearest match!"}`); | ||
| (0, _tanstack_router_core.invariant)(); | ||
| if (!match) { | ||
| if (opts.shouldThrow ?? true) { | ||
| if (process.env.NODE_ENV !== "production") throw new Error(`Invariant failed: Could not find ${opts.from ? `an active match from "${opts.from}"` : "a nearest match!"}`); | ||
| (0, _tanstack_router_core.invariant)(); | ||
| } | ||
| return; | ||
| } | ||
| if (match === void 0) return; | ||
| return opts.select ? opts.select(match) : match; | ||
| } | ||
| const previousResult = react.useRef(void 0); | ||
| return (0, _tanstack_react_store.useStore)(matchStore ?? dummyStore, (match) => { | ||
| if ((opts.shouldThrow ?? true) && !match) { | ||
| if (process.env.NODE_ENV !== "production") throw new Error(`Invariant failed: Could not find ${opts.from ? `an active match from "${opts.from}"` : "a nearest match!"}`); | ||
| (0, _tanstack_router_core.invariant)(); | ||
| } | ||
| if (match === void 0) return; | ||
| const selected = opts.select ? opts.select(match) : match; | ||
| if (opts.structuralSharing ?? router.options.defaultStructuralSharing) { | ||
| const shared = (0, _tanstack_router_core.replaceEqualDeep)(previousResult.current, selected); | ||
| previousResult.current = shared; | ||
| return shared; | ||
| } | ||
| return selected; | ||
| }); | ||
| const selector = useStructuralSharing(opts, router); | ||
| const matchSelection = (0, _tanstack_react_store.useStore)(matchStore ?? dummyStore, (match) => match ? selector(match) : dummyStore); | ||
| if (matchSelection !== dummyStore) return matchSelection; | ||
| if (opts.shouldThrow ?? true) { | ||
| if (process.env.NODE_ENV !== "production") throw new Error(`Invariant failed: Could not find ${opts.from ? `an active match from "${opts.from}"` : "a nearest match!"}`); | ||
| (0, _tanstack_router_core.invariant)(); | ||
| } | ||
| } | ||
| //#endregion | ||
| exports.useMatch = useMatch; | ||
| exports.useStructuralSharing = useStructuralSharing; | ||
| //# sourceMappingURL=useMatch.cjs.map |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"useMatch.cjs","names":[],"sources":["../../src/useMatch.tsx"],"sourcesContent":["'use client'\n\nimport * as React from 'react'\nimport { useStore } from '@tanstack/react-store'\nimport { invariant, replaceEqualDeep } from '@tanstack/router-core'\nimport { isServer } from '@tanstack/router-core/isServer'\nimport { dummyMatchContext, matchContext } from './matchContext'\nimport { useRouter } from './useRouter'\nimport type {\n StructuralSharingOption,\n ValidateSelected,\n} from './structuralSharing'\nimport type {\n AnyRouter,\n MakeRouteMatch,\n MakeRouteMatchUnion,\n RegisteredRouter,\n StrictOrFrom,\n ThrowConstraint,\n ThrowOrOptional,\n} from '@tanstack/router-core'\n\nconst dummyStore = {\n get: () => undefined,\n subscribe: () => ({ unsubscribe: () => {} }),\n} as any\n\nexport interface UseMatchBaseOptions<\n TRouter extends AnyRouter,\n TFrom,\n TStrict extends boolean,\n TThrow extends boolean,\n TSelected,\n TStructuralSharing extends boolean,\n> {\n select?: (\n match: MakeRouteMatch<TRouter['routeTree'], TFrom, TStrict>,\n ) => ValidateSelected<TRouter, TSelected, TStructuralSharing>\n shouldThrow?: TThrow\n}\n\nexport type UseMatchRoute<out TFrom> = <\n TRouter extends AnyRouter = RegisteredRouter,\n TSelected = unknown,\n TStructuralSharing extends boolean = boolean,\n>(\n opts?: UseMatchBaseOptions<\n TRouter,\n TFrom,\n true,\n true,\n TSelected,\n TStructuralSharing\n > &\n StructuralSharingOption<TRouter, TSelected, TStructuralSharing>,\n) => UseMatchResult<TRouter, TFrom, true, TSelected>\n\nexport type UseMatchOptions<\n TRouter extends AnyRouter,\n TFrom extends string | undefined,\n TStrict extends boolean,\n TThrow extends boolean,\n TSelected,\n TStructuralSharing extends boolean,\n> = StrictOrFrom<TRouter, TFrom, TStrict> &\n UseMatchBaseOptions<\n TRouter,\n TFrom,\n TStrict,\n TThrow,\n TSelected,\n TStructuralSharing\n > &\n StructuralSharingOption<TRouter, TSelected, TStructuralSharing>\n\nexport type UseMatchResult<\n TRouter extends AnyRouter,\n TFrom,\n TStrict extends boolean,\n TSelected,\n> = unknown extends TSelected\n ? TStrict extends true\n ? MakeRouteMatch<TRouter['routeTree'], TFrom, TStrict>\n : MakeRouteMatchUnion<TRouter>\n : TSelected\n\n/**\n * Read and select the nearest or targeted route match.\n * @link https://tanstack.com/router/latest/docs/framework/react/api/router/useMatchHook\n */\nexport function useMatch<\n TRouter extends AnyRouter = RegisteredRouter,\n const TFrom extends string | undefined = undefined,\n TStrict extends boolean = true,\n TThrow extends boolean = true,\n TSelected = unknown,\n TStructuralSharing extends boolean = boolean,\n>(\n opts: UseMatchOptions<\n TRouter,\n TFrom,\n TStrict,\n ThrowConstraint<TStrict, TThrow>,\n TSelected,\n TStructuralSharing\n >,\n): ThrowOrOptional<UseMatchResult<TRouter, TFrom, TStrict, TSelected>, TThrow> {\n const router = useRouter<TRouter>()\n const nearestMatchId = React.useContext(\n opts.from ? dummyMatchContext : matchContext,\n )\n\n const key = opts.from ?? nearestMatchId\n const matchStore = key\n ? opts.from\n ? router.stores.getRouteMatchStore(key)\n : router.stores.matchStores.get(key)\n : undefined\n\n if (isServer ?? router.isServer) {\n const match = matchStore?.get()\n if ((opts.shouldThrow ?? true) && !match) {\n if (process.env.NODE_ENV !== 'production') {\n throw new Error(\n `Invariant failed: Could not find ${opts.from ? `an active match from \"${opts.from}\"` : 'a nearest match!'}`,\n )\n }\n\n invariant()\n }\n\n if (match === undefined) {\n return undefined as any\n }\n\n return (opts.select ? opts.select(match as any) : match) as any\n }\n\n const previousResult =\n // eslint-disable-next-line react-hooks/rules-of-hooks -- condition is static\n React.useRef<ValidateSelected<TRouter, TSelected, TStructuralSharing>>(\n undefined,\n )\n\n // eslint-disable-next-line react-hooks/rules-of-hooks -- condition is static\n return useStore(matchStore ?? dummyStore, (match) => {\n if ((opts.shouldThrow ?? true) && !match) {\n if (process.env.NODE_ENV !== 'production') {\n throw new Error(\n `Invariant failed: Could not find ${opts.from ? `an active match from \"${opts.from}\"` : 'a nearest match!'}`,\n )\n }\n\n invariant()\n }\n\n if (match === undefined) {\n return undefined\n }\n\n const selected = (\n opts.select ? opts.select(match as any) : match\n ) as ValidateSelected<TRouter, TSelected, TStructuralSharing>\n\n if (opts.structuralSharing ?? router.options.defaultStructuralSharing) {\n const shared = replaceEqualDeep(previousResult.current, selected)\n previousResult.current = shared\n return shared\n }\n\n return selected\n }) as any\n}\n"],"mappings":";;;;;;;;;;AAsBA,IAAM,aAAa;CACjB,WAAW,KAAA;CACX,kBAAkB,EAAE,mBAAmB,CAAC,EAAE;AAC5C;;;;;AAiEA,SAAgB,SAQd,MAQ6E;CAC7E,MAAM,SAAS,kBAAA,UAAmB;CAClC,MAAM,iBAAiB,MAAM,WAC3B,KAAK,OAAO,qBAAA,oBAAoB,qBAAA,YAClC;CAEA,MAAM,MAAM,KAAK,QAAQ;CACzB,MAAM,aAAa,MACf,KAAK,OACH,OAAO,OAAO,mBAAmB,GAAG,IACpC,OAAO,OAAO,YAAY,IAAI,GAAG,IACnC,KAAA;CAEJ,IAAI,+BAAA,YAAY,OAAO,UAAU;EAC/B,MAAM,QAAQ,YAAY,IAAI;EAC9B,KAAK,KAAK,eAAe,SAAS,CAAC,OAAO;GACxC,IAAA,QAAA,IAAA,aAA6B,cAC3B,MAAM,IAAI,MACR,oCAAoC,KAAK,OAAO,yBAAyB,KAAK,KAAK,KAAK,oBAC1F;GAGF,CAAA,GAAA,sBAAA,WAAU;EACZ;EAEA,IAAI,UAAU,KAAA,GACZ;EAGF,OAAQ,KAAK,SAAS,KAAK,OAAO,KAAY,IAAI;CACpD;CAEA,MAAM,iBAEJ,MAAM,OACJ,KAAA,CACF;CAGF,QAAA,GAAA,sBAAA,UAAgB,cAAc,aAAa,UAAU;EACnD,KAAK,KAAK,eAAe,SAAS,CAAC,OAAO;GACxC,IAAA,QAAA,IAAA,aAA6B,cAC3B,MAAM,IAAI,MACR,oCAAoC,KAAK,OAAO,yBAAyB,KAAK,KAAK,KAAK,oBAC1F;GAGF,CAAA,GAAA,sBAAA,WAAU;EACZ;EAEA,IAAI,UAAU,KAAA,GACZ;EAGF,MAAM,WACJ,KAAK,SAAS,KAAK,OAAO,KAAY,IAAI;EAG5C,IAAI,KAAK,qBAAqB,OAAO,QAAQ,0BAA0B;GACrE,MAAM,UAAA,GAAA,sBAAA,kBAA0B,eAAe,SAAS,QAAQ;GAChE,eAAe,UAAU;GACzB,OAAO;EACT;EAEA,OAAO;CACT,CAAC;AACH"} | ||
| {"version":3,"file":"useMatch.cjs","names":[],"sources":["../../src/useMatch.tsx"],"sourcesContent":["'use client'\n\nimport * as React from 'react'\nimport { useStore } from '@tanstack/react-store'\nimport { invariant, replaceEqualDeep } from '@tanstack/router-core'\nimport { isServer } from '@tanstack/router-core/isServer'\nimport { dummyMatchContext, matchContext } from './matchContext'\nimport { useRouter } from './useRouter'\nimport type {\n StructuralSharingOption,\n ValidateSelected,\n} from './structuralSharing'\nimport type {\n AnyRouter,\n MakeRouteMatch,\n MakeRouteMatchUnion,\n RegisteredRouter,\n StrictOrFrom,\n ThrowConstraint,\n ThrowOrOptional,\n} from '@tanstack/router-core'\n\nconst dummyStore = {\n get() {},\n subscribe() {\n return { unsubscribe() {} }\n },\n} as any\n\nexport function useStructuralSharing<\n TRouter extends AnyRouter,\n TSelected,\n TStructuralSharing extends boolean,\n TStoreSlice,\n TSelectSlice = TStoreSlice,\n>(\n opts:\n | {\n select?: (\n slice: TSelectSlice,\n ) => ValidateSelected<TRouter, TSelected, TStructuralSharing>\n structuralSharing?: boolean\n }\n | undefined,\n router: TRouter,\n): (\n slice: TStoreSlice,\n) => ValidateSelected<TRouter, TSelected, TStructuralSharing> {\n const previousResult =\n // @ts-expect-error -- init to undefined, but without writing `undefined` to shave bytes\n React.useRef<ValidateSelected<TRouter, TSelected, TStructuralSharing>>()\n\n return (slice) => {\n const selected = opts?.select\n ? opts.select(slice as unknown as TSelectSlice)\n : (slice as ValidateSelected<TRouter, TSelected, TStructuralSharing>)\n\n if (opts?.structuralSharing ?? router.options.defaultStructuralSharing) {\n return (previousResult.current = replaceEqualDeep(\n previousResult.current,\n selected,\n ))\n }\n\n return selected\n }\n}\n\nexport interface UseMatchBaseOptions<\n TRouter extends AnyRouter,\n TFrom,\n TStrict extends boolean,\n TThrow extends boolean,\n TSelected,\n TStructuralSharing extends boolean,\n> {\n select?: (\n match: MakeRouteMatch<TRouter['routeTree'], TFrom, TStrict>,\n ) => ValidateSelected<TRouter, TSelected, TStructuralSharing>\n shouldThrow?: TThrow\n}\n\nexport type UseMatchRoute<out TFrom> = <\n TRouter extends AnyRouter = RegisteredRouter,\n TSelected = unknown,\n TStructuralSharing extends boolean = boolean,\n>(\n opts?: UseMatchBaseOptions<\n TRouter,\n TFrom,\n true,\n true,\n TSelected,\n TStructuralSharing\n > &\n StructuralSharingOption<TRouter, TSelected, TStructuralSharing>,\n) => UseMatchResult<TRouter, TFrom, true, TSelected>\n\nexport type UseMatchOptions<\n TRouter extends AnyRouter,\n TFrom extends string | undefined,\n TStrict extends boolean,\n TThrow extends boolean,\n TSelected,\n TStructuralSharing extends boolean,\n> = StrictOrFrom<TRouter, TFrom, TStrict> &\n UseMatchBaseOptions<\n TRouter,\n TFrom,\n TStrict,\n TThrow,\n TSelected,\n TStructuralSharing\n > &\n StructuralSharingOption<TRouter, TSelected, TStructuralSharing>\n\nexport type UseMatchResult<\n TRouter extends AnyRouter,\n TFrom,\n TStrict extends boolean,\n TSelected,\n> = unknown extends TSelected\n ? TStrict extends true\n ? MakeRouteMatch<TRouter['routeTree'], TFrom, TStrict>\n : MakeRouteMatchUnion<TRouter>\n : TSelected\n\n/**\n * Read and select the nearest or targeted route match.\n * @link https://tanstack.com/router/latest/docs/framework/react/api/router/useMatchHook\n */\nexport function useMatch<\n TRouter extends AnyRouter = RegisteredRouter,\n const TFrom extends string | undefined = undefined,\n TStrict extends boolean = true,\n TThrow extends boolean = true,\n TSelected = unknown,\n TStructuralSharing extends boolean = boolean,\n>(\n opts: UseMatchOptions<\n TRouter,\n TFrom,\n TStrict,\n ThrowConstraint<TStrict, TThrow>,\n TSelected,\n TStructuralSharing\n >,\n): ThrowOrOptional<UseMatchResult<TRouter, TFrom, TStrict, TSelected>, TThrow> {\n const router = useRouter<TRouter>()\n const nearestMatchId = React.useContext(\n opts.from ? dummyMatchContext : matchContext,\n )\n\n const matchStore = opts.from\n ? router.stores.getRouteMatchStore(opts.from)\n : router.stores.matchStores.get(nearestMatchId!)\n\n if (isServer ?? router.isServer) {\n const match = matchStore?.get()\n if (!match) {\n if (opts.shouldThrow ?? true) {\n if (process.env.NODE_ENV !== 'production') {\n throw new Error(\n `Invariant failed: Could not find ${opts.from ? `an active match from \"${opts.from}\"` : 'a nearest match!'}`,\n )\n }\n\n invariant()\n }\n\n return undefined as any\n }\n\n return (opts.select ? opts.select(match as any) : match) as any\n }\n\n const selector =\n // eslint-disable-next-line react-hooks/rules-of-hooks -- condition is static\n useStructuralSharing(opts, router)\n\n // eslint-disable-next-line react-hooks/rules-of-hooks -- condition is static\n const matchSelection = useStore(matchStore ?? dummyStore, (match) =>\n match ? selector(match as any) : dummyStore,\n )\n\n if (matchSelection !== dummyStore) {\n return matchSelection\n }\n\n if (opts.shouldThrow ?? true) {\n if (process.env.NODE_ENV !== 'production') {\n throw new Error(\n `Invariant failed: Could not find ${opts.from ? `an active match from \"${opts.from}\"` : 'a nearest match!'}`,\n )\n }\n\n invariant()\n }\n\n return undefined as any\n}\n"],"mappings":";;;;;;;;;;AAsBA,IAAM,aAAa;CACjB,MAAM,CAAC;CACP,YAAY;EACV,OAAO,EAAE,cAAc,CAAC,EAAE;CAC5B;AACF;AAEA,SAAgB,qBAOd,MAQA,QAG4D;CAC5D,MAAM,iBAEJ,MAAM,OAAiE;CAEzE,QAAQ,UAAU;EAChB,MAAM,WAAW,MAAM,SACnB,KAAK,OAAO,KAAgC,IAC3C;EAEL,IAAI,MAAM,qBAAqB,OAAO,QAAQ,0BAC5C,OAAQ,eAAe,WAAA,GAAA,sBAAA,kBACrB,eAAe,SACf,QACF;EAGF,OAAO;CACT;AACF;;;;;AAiEA,SAAgB,SAQd,MAQ6E;CAC7E,MAAM,SAAS,kBAAA,UAAmB;CAClC,MAAM,iBAAiB,MAAM,WAC3B,KAAK,OAAO,qBAAA,oBAAoB,qBAAA,YAClC;CAEA,MAAM,aAAa,KAAK,OACpB,OAAO,OAAO,mBAAmB,KAAK,IAAI,IAC1C,OAAO,OAAO,YAAY,IAAI,cAAe;CAEjD,IAAI,+BAAA,YAAY,OAAO,UAAU;EAC/B,MAAM,QAAQ,YAAY,IAAI;EAC9B,IAAI,CAAC,OAAO;GACV,IAAI,KAAK,eAAe,MAAM;IAC5B,IAAA,QAAA,IAAA,aAA6B,cAC3B,MAAM,IAAI,MACR,oCAAoC,KAAK,OAAO,yBAAyB,KAAK,KAAK,KAAK,oBAC1F;IAGF,CAAA,GAAA,sBAAA,WAAU;GACZ;GAEA;EACF;EAEA,OAAQ,KAAK,SAAS,KAAK,OAAO,KAAY,IAAI;CACpD;CAEA,MAAM,WAEJ,qBAAqB,MAAM,MAAM;CAGnC,MAAM,kBAAA,GAAA,sBAAA,UAA0B,cAAc,aAAa,UACzD,QAAQ,SAAS,KAAY,IAAI,UACnC;CAEA,IAAI,mBAAmB,YACrB,OAAO;CAGT,IAAI,KAAK,eAAe,MAAM;EAC5B,IAAA,QAAA,IAAA,aAA6B,cAC3B,MAAM,IAAI,MACR,oCAAoC,KAAK,OAAO,yBAAyB,KAAK,KAAK,KAAK,oBAC1F;EAGF,CAAA,GAAA,sBAAA,WAAU;CACZ;AAGF"} |
| import { StructuralSharingOption, ValidateSelected } from './structuralSharing.cjs'; | ||
| import { AnyRouter, MakeRouteMatch, MakeRouteMatchUnion, RegisteredRouter, StrictOrFrom, ThrowConstraint, ThrowOrOptional } from '@tanstack/router-core'; | ||
| export declare function useStructuralSharing<TRouter extends AnyRouter, TSelected, TStructuralSharing extends boolean, TStoreSlice, TSelectSlice = TStoreSlice>(opts: { | ||
| select?: (slice: TSelectSlice) => ValidateSelected<TRouter, TSelected, TStructuralSharing>; | ||
| structuralSharing?: boolean; | ||
| } | undefined, router: TRouter): (slice: TStoreSlice) => ValidateSelected<TRouter, TSelected, TStructuralSharing>; | ||
| export interface UseMatchBaseOptions<TRouter extends AnyRouter, TFrom, TStrict extends boolean, TThrow extends boolean, TSelected, TStructuralSharing extends boolean> { | ||
@@ -4,0 +8,0 @@ select?: (match: MakeRouteMatch<TRouter['routeTree'], TFrom, TStrict>) => ValidateSelected<TRouter, TSelected, TStructuralSharing>; |
| "use client"; | ||
| const require_useRouter = require("./useRouter.cjs"); | ||
| let _tanstack_router_core = require("@tanstack/router-core"); | ||
| let react = require("react"); | ||
| const require_useMatch = require("./useMatch.cjs"); | ||
| let _tanstack_react_store = require("@tanstack/react-store"); | ||
@@ -27,14 +26,3 @@ let _tanstack_router_core_isServer = require("@tanstack/router-core/isServer"); | ||
| } | ||
| const previousResult = (0, react.useRef)(void 0); | ||
| return (0, _tanstack_react_store.useStore)(router.stores.__store, (state) => { | ||
| if (opts?.select) { | ||
| if (opts.structuralSharing ?? router.options.defaultStructuralSharing) { | ||
| const newSlice = (0, _tanstack_router_core.replaceEqualDeep)(previousResult.current, opts.select(state)); | ||
| previousResult.current = newSlice; | ||
| return newSlice; | ||
| } | ||
| return opts.select(state); | ||
| } | ||
| return state; | ||
| }); | ||
| return (0, _tanstack_react_store.useStore)(router.stores.__store, require_useMatch.useStructuralSharing(opts, router)); | ||
| } | ||
@@ -41,0 +29,0 @@ //#endregion |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"useRouterState.cjs","names":[],"sources":["../../src/useRouterState.tsx"],"sourcesContent":["'use client'\n\nimport { useStore } from '@tanstack/react-store'\nimport { useRef } from 'react'\nimport { replaceEqualDeep } from '@tanstack/router-core'\nimport { isServer } from '@tanstack/router-core/isServer'\nimport { useRouter } from './useRouter'\nimport type {\n AnyRouter,\n RegisteredRouter,\n RouterState,\n} from '@tanstack/router-core'\nimport type {\n StructuralSharingOption,\n ValidateSelected,\n} from './structuralSharing'\n\nexport type UseRouterStateOptions<\n TRouter extends AnyRouter,\n TSelected,\n TStructuralSharing,\n> = {\n router?: TRouter\n select?: (\n state: RouterState<TRouter['routeTree']>,\n ) => ValidateSelected<TRouter, TSelected, TStructuralSharing>\n} & StructuralSharingOption<TRouter, TSelected, TStructuralSharing>\n\nexport type UseRouterStateResult<\n TRouter extends AnyRouter,\n TSelected,\n> = unknown extends TSelected ? RouterState<TRouter['routeTree']> : TSelected\n\n/**\n * Subscribe to the router's state store with optional selection and\n * structural sharing for render optimization.\n *\n * Options:\n * - `select`: Project the full router state to a derived slice\n * - `structuralSharing`: Replace-equal semantics for stable references\n * - `router`: Read state from a specific router instance instead of context\n *\n * @returns The selected router state (or the full state by default).\n * @link https://tanstack.com/router/latest/docs/framework/react/api/router/useRouterStateHook\n */\nexport function useRouterState<\n TRouter extends AnyRouter = RegisteredRouter,\n TSelected = unknown,\n TStructuralSharing extends boolean = boolean,\n>(\n opts?: UseRouterStateOptions<TRouter, TSelected, TStructuralSharing>,\n): UseRouterStateResult<TRouter, TSelected> {\n const contextRouter = useRouter<TRouter>({\n warn: opts?.router === undefined,\n })\n const router = opts?.router || contextRouter\n\n // During SSR we render exactly once and do not need reactivity.\n // Avoid subscribing to the store (and any structural sharing work) on the server.\n const _isServer = isServer ?? router.isServer\n if (_isServer) {\n const state = router.stores.__store.get() as RouterState<\n TRouter['routeTree']\n >\n return (opts?.select ? opts.select(state) : state) as UseRouterStateResult<\n TRouter,\n TSelected\n >\n }\n\n const previousResult =\n // eslint-disable-next-line react-hooks/rules-of-hooks\n useRef<ValidateSelected<TRouter, TSelected, TStructuralSharing>>(undefined)\n\n // eslint-disable-next-line react-hooks/rules-of-hooks\n return useStore(router.stores.__store, (state) => {\n if (opts?.select) {\n if (opts.structuralSharing ?? router.options.defaultStructuralSharing) {\n const newSlice = replaceEqualDeep(\n previousResult.current,\n opts.select(state),\n )\n previousResult.current = newSlice\n return newSlice\n }\n return opts.select(state)\n }\n return state\n }) as UseRouterStateResult<TRouter, TSelected>\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;AA6CA,SAAgB,eAKd,MAC0C;CAC1C,MAAM,gBAAgB,kBAAA,UAAmB,EACvC,MAAM,MAAM,WAAW,KAAA,EACzB,CAAC;CACD,MAAM,SAAS,MAAM,UAAU;CAK/B,IADkB,+BAAA,YAAY,OAAO,UACtB;EACb,MAAM,QAAQ,OAAO,OAAO,QAAQ,IAAI;EAGxC,OAAQ,MAAM,SAAS,KAAK,OAAO,KAAK,IAAI;CAI9C;CAEA,MAAM,kBAAA,GAAA,MAAA,QAE6D,KAAA,CAAS;CAG5E,QAAA,GAAA,sBAAA,UAAgB,OAAO,OAAO,UAAU,UAAU;EAChD,IAAI,MAAM,QAAQ;GAChB,IAAI,KAAK,qBAAqB,OAAO,QAAQ,0BAA0B;IACrE,MAAM,YAAA,GAAA,sBAAA,kBACJ,eAAe,SACf,KAAK,OAAO,KAAK,CACnB;IACA,eAAe,UAAU;IACzB,OAAO;GACT;GACA,OAAO,KAAK,OAAO,KAAK;EAC1B;EACA,OAAO;CACT,CAAC;AACH"} | ||
| {"version":3,"file":"useRouterState.cjs","names":[],"sources":["../../src/useRouterState.tsx"],"sourcesContent":["'use client'\n\nimport { useStore } from '@tanstack/react-store'\nimport { isServer } from '@tanstack/router-core/isServer'\nimport { useRouter } from './useRouter'\nimport { useStructuralSharing } from './useMatch'\nimport type {\n AnyRouter,\n RegisteredRouter,\n RouterState,\n} from '@tanstack/router-core'\nimport type {\n StructuralSharingOption,\n ValidateSelected,\n} from './structuralSharing'\n\nexport type UseRouterStateOptions<\n TRouter extends AnyRouter,\n TSelected,\n TStructuralSharing,\n> = {\n router?: TRouter\n select?: (\n state: RouterState<TRouter['routeTree']>,\n ) => ValidateSelected<TRouter, TSelected, TStructuralSharing>\n} & StructuralSharingOption<TRouter, TSelected, TStructuralSharing>\n\nexport type UseRouterStateResult<\n TRouter extends AnyRouter,\n TSelected,\n> = unknown extends TSelected ? RouterState<TRouter['routeTree']> : TSelected\n\n/**\n * Subscribe to the router's state store with optional selection and\n * structural sharing for render optimization.\n *\n * Options:\n * - `select`: Project the full router state to a derived slice\n * - `structuralSharing`: Replace-equal semantics for stable references\n * - `router`: Read state from a specific router instance instead of context\n *\n * @returns The selected router state (or the full state by default).\n * @link https://tanstack.com/router/latest/docs/framework/react/api/router/useRouterStateHook\n */\nexport function useRouterState<\n TRouter extends AnyRouter = RegisteredRouter,\n TSelected = unknown,\n TStructuralSharing extends boolean = boolean,\n>(\n opts?: UseRouterStateOptions<TRouter, TSelected, TStructuralSharing>,\n): UseRouterStateResult<TRouter, TSelected> {\n const contextRouter = useRouter<TRouter>({\n warn: opts?.router === undefined,\n })\n const router = opts?.router || contextRouter\n\n // During SSR we render exactly once and do not need reactivity.\n // Avoid subscribing to the store (and any structural sharing work) on the server.\n const _isServer = isServer ?? router.isServer\n if (_isServer) {\n const state = router.stores.__store.get() as RouterState<\n TRouter['routeTree']\n >\n return (opts?.select ? opts.select(state) : state) as UseRouterStateResult<\n TRouter,\n TSelected\n >\n }\n\n // eslint-disable-next-line react-hooks/rules-of-hooks -- condition is static\n return useStore(\n router.stores.__store,\n // eslint-disable-next-line react-hooks/rules-of-hooks -- condition is static\n useStructuralSharing(opts, router),\n ) as UseRouterStateResult<TRouter, TSelected>\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AA4CA,SAAgB,eAKd,MAC0C;CAC1C,MAAM,gBAAgB,kBAAA,UAAmB,EACvC,MAAM,MAAM,WAAW,KAAA,EACzB,CAAC;CACD,MAAM,SAAS,MAAM,UAAU;CAK/B,IADkB,+BAAA,YAAY,OAAO,UACtB;EACb,MAAM,QAAQ,OAAO,OAAO,QAAQ,IAAI;EAGxC,OAAQ,MAAM,SAAS,KAAK,OAAO,KAAK,IAAI;CAI9C;CAGA,QAAA,GAAA,sBAAA,UACE,OAAO,OAAO,SAEd,iBAAA,qBAAqB,MAAM,MAAM,CACnC;AACF"} |
+15
-18
@@ -17,2 +17,4 @@ "use client"; | ||
| //#region src/Match.tsx | ||
| var matchViewFieldsEqual = (a, b) => a.routeId === b.routeId && a._displayPending === b._displayPending; | ||
| var outletMatchSelectionEqual = (a, b) => a[0] === b[0] && a[1] === b[1]; | ||
| var Match = React$1.memo(function MatchImpl({ matchId }) { | ||
@@ -46,3 +48,3 @@ const router = useRouter(); | ||
| const resetKey = useStore(router.stores.loadedAt, (loadedAt) => loadedAt); | ||
| const match = useStore(matchStore, (value) => value); | ||
| const match = useStore(matchStore, (value) => value, matchViewFieldsEqual); | ||
| return /* @__PURE__ */ jsx(MatchView, { | ||
@@ -108,22 +110,17 @@ router, | ||
| }) | ||
| }), matchState.parentRouteId === rootRouteId ? /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(OnRendered, { resetKey }), router.options.scrollRestoration && (isServer ?? router.isServer) ? /* @__PURE__ */ jsx(ScrollRestoration, {}) : null] }) : null] }); | ||
| }), matchState.parentRouteId === rootRouteId ? /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(OnRendered, {}), router.options.scrollRestoration && (isServer ?? router.isServer) ? /* @__PURE__ */ jsx(ScrollRestoration, {}) : null] }) : null] }); | ||
| } | ||
| function OnRendered({ resetKey }) { | ||
| function OnRendered() { | ||
| const router = useRouter(); | ||
| if (isServer ?? router.isServer) return null; | ||
| const prevHrefRef = React$1.useRef(void 0); | ||
| const prevResolvedLocationRef = React$1.useRef(); | ||
| useLayoutEffect(() => { | ||
| const currentHref = router.latestLocation.href; | ||
| if (prevHrefRef.current === void 0 || prevHrefRef.current !== currentHref) { | ||
| router.emit({ | ||
| type: "onRendered", | ||
| ...getLocationChangeInfo(router.stores.location.get(), router.stores.resolvedLocation.get()) | ||
| }); | ||
| prevHrefRef.current = currentHref; | ||
| } | ||
| }, [ | ||
| router.latestLocation.state.__TSR_key, | ||
| resetKey, | ||
| router | ||
| ]); | ||
| const currentResolvedLocation = router.stores.resolvedLocation.get(); | ||
| const previousResolvedLocation = prevResolvedLocationRef.current; | ||
| if (currentResolvedLocation && (!previousResolvedLocation || previousResolvedLocation.href !== currentResolvedLocation.href)) router.emit({ | ||
| type: "onRendered", | ||
| ...getLocationChangeInfo(router.stores.location.get(), previousResolvedLocation ?? currentResolvedLocation) | ||
| }); | ||
| prevResolvedLocationRef.current = currentResolvedLocation; | ||
| }, [useStore(router.stores.resolvedLocation, (resolvedLocation) => resolvedLocation?.state.__TSR_key), router]); | ||
| return null; | ||
@@ -274,3 +271,3 @@ } | ||
| const parentMatchStore = matchId ? router.stores.matchStores.get(matchId) : void 0; | ||
| [routeId, parentGlobalNotFound] = useStore(parentMatchStore, (match) => [match?.routeId, match?.globalNotFound ?? false]); | ||
| [routeId, parentGlobalNotFound] = useStore(parentMatchStore, (match) => [match?.routeId, match?.globalNotFound ?? false], outletMatchSelectionEqual); | ||
| childMatchId = useStore(router.stores.matchesId, (ids) => { | ||
@@ -277,0 +274,0 @@ return ids[ids.findIndex((id) => id === matchId) + 1]; |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"Match.js","names":[],"sources":["../../src/Match.tsx"],"sourcesContent":["'use client'\n\nimport * as React from 'react'\nimport { useStore } from '@tanstack/react-store'\nimport {\n createControlledPromise,\n getLocationChangeInfo,\n invariant,\n isNotFound,\n isRedirect,\n rootRouteId,\n} from '@tanstack/router-core'\nimport { isServer } from '@tanstack/router-core/isServer'\nimport { CatchBoundary, ErrorComponent } from './CatchBoundary'\nimport { useRouter } from './useRouter'\nimport { CatchNotFound } from './not-found'\nimport { matchContext } from './matchContext'\nimport { SafeFragment } from './SafeFragment'\nimport { renderRouteNotFound } from './renderRouteNotFound'\nimport { ScrollRestoration } from './scroll-restoration'\nimport { ClientOnly } from './ClientOnly'\nimport { useLayoutEffect } from './utils'\nimport type { AnyRoute, RootRouteOptions } from '@tanstack/router-core'\n\nexport const Match = React.memo(function MatchImpl({\n matchId,\n}: {\n matchId: string\n}) {\n const router = useRouter()\n\n if (isServer ?? router.isServer) {\n const match = router.stores.matchStores.get(matchId)?.get()\n if (!match) {\n if (process.env.NODE_ENV !== 'production') {\n throw new Error(\n `Invariant failed: Could not find match for matchId \"${matchId}\". Please file an issue!`,\n )\n }\n\n invariant()\n }\n\n const routeId = match.routeId as string\n const parentRouteId = (router.routesById[routeId] as AnyRoute).parentRoute\n ?.id\n\n return (\n <MatchView\n router={router}\n matchId={matchId}\n resetKey={router.stores.loadedAt.get()}\n matchState={{\n routeId,\n ssr: match.ssr,\n _displayPending: match._displayPending,\n parentRouteId,\n }}\n />\n )\n }\n\n // Subscribe directly to the match store from the pool.\n // The matchId prop is stable for this component's lifetime (set by Outlet),\n // and reconcileMatchPool reuses stores for the same matchId.\n\n const matchStore = router.stores.matchStores.get(matchId)\n if (!matchStore) {\n if (process.env.NODE_ENV !== 'production') {\n throw new Error(\n `Invariant failed: Could not find match for matchId \"${matchId}\". Please file an issue!`,\n )\n }\n\n invariant()\n }\n // eslint-disable-next-line react-hooks/rules-of-hooks\n const resetKey = useStore(router.stores.loadedAt, (loadedAt) => loadedAt)\n // eslint-disable-next-line react-hooks/rules-of-hooks\n const match = useStore(matchStore, (value) => value)\n // eslint-disable-next-line react-hooks/rules-of-hooks\n const matchState = React.useMemo(() => {\n const routeId = match.routeId as string\n const parentRouteId = (router.routesById[routeId] as AnyRoute).parentRoute\n ?.id\n\n return {\n routeId,\n ssr: match.ssr,\n _displayPending: match._displayPending,\n parentRouteId: parentRouteId as string | undefined,\n } satisfies MatchViewState\n }, [match._displayPending, match.routeId, match.ssr, router.routesById])\n\n return (\n <MatchView\n router={router}\n matchId={matchId}\n resetKey={resetKey}\n matchState={matchState}\n />\n )\n})\n\ntype MatchViewState = {\n routeId: string\n ssr: boolean | 'data-only' | undefined\n _displayPending: boolean | undefined\n parentRouteId: string | undefined\n}\n\nfunction MatchView({\n router,\n matchId,\n resetKey,\n matchState,\n}: {\n router: ReturnType<typeof useRouter>\n matchId: string\n resetKey: number\n matchState: MatchViewState\n}) {\n const route: AnyRoute = router.routesById[matchState.routeId]\n\n const PendingComponent =\n route.options.pendingComponent ?? router.options.defaultPendingComponent\n\n const pendingElement = PendingComponent ? <PendingComponent /> : null\n\n const routeErrorComponent =\n route.options.errorComponent ?? router.options.defaultErrorComponent\n\n const routeOnCatch = route.options.onCatch ?? router.options.defaultOnCatch\n\n const routeNotFoundComponent = route.isRoot\n ? // If it's the root route, use the globalNotFound option, with fallback to the notFoundRoute's component\n (route.options.notFoundComponent ??\n router.options.notFoundRoute?.options.component)\n : route.options.notFoundComponent\n\n const resolvedNoSsr =\n matchState.ssr === false || matchState.ssr === 'data-only'\n const ResolvedSuspenseBoundary =\n // If we're on the root route, allow forcefully wrapping in suspense\n (!route.isRoot || route.options.wrapInSuspense || resolvedNoSsr) &&\n (route.options.wrapInSuspense ??\n PendingComponent ??\n ((route.options.errorComponent as any)?.preload || resolvedNoSsr))\n ? React.Suspense\n : SafeFragment\n\n const ResolvedCatchBoundary = routeErrorComponent\n ? CatchBoundary\n : SafeFragment\n\n const ResolvedNotFoundBoundary = routeNotFoundComponent\n ? CatchNotFound\n : SafeFragment\n\n const ShellComponent = route.isRoot\n ? ((route.options as RootRouteOptions).shellComponent ?? SafeFragment)\n : SafeFragment\n return (\n <ShellComponent>\n <matchContext.Provider value={matchId}>\n <ResolvedSuspenseBoundary fallback={pendingElement}>\n <ResolvedCatchBoundary\n getResetKey={() => resetKey}\n errorComponent={routeErrorComponent || ErrorComponent}\n onCatch={(error, errorInfo) => {\n // Forward not found errors (we don't want to show the error component for these)\n if (isNotFound(error)) {\n error.routeId ??= matchState.routeId as any\n throw error\n }\n if (process.env.NODE_ENV !== 'production') {\n console.warn(`Warning: Error in route match: ${matchId}`)\n }\n routeOnCatch?.(error, errorInfo)\n }}\n >\n <ResolvedNotFoundBoundary\n fallback={(error) => {\n error.routeId ??= matchState.routeId as any\n\n // If the current not found handler doesn't exist or it has a\n // route ID which doesn't match the current route, rethrow the error\n if (\n !routeNotFoundComponent ||\n (error.routeId && error.routeId !== matchState.routeId) ||\n (!error.routeId && !route.isRoot)\n )\n throw error\n\n return React.createElement(routeNotFoundComponent, error as any)\n }}\n >\n {resolvedNoSsr || matchState._displayPending ? (\n <ClientOnly fallback={pendingElement}>\n <MatchInner matchId={matchId} />\n </ClientOnly>\n ) : (\n <MatchInner matchId={matchId} />\n )}\n </ResolvedNotFoundBoundary>\n </ResolvedCatchBoundary>\n </ResolvedSuspenseBoundary>\n </matchContext.Provider>\n {matchState.parentRouteId === rootRouteId ? (\n <>\n <OnRendered resetKey={resetKey} />\n {router.options.scrollRestoration && (isServer ?? router.isServer) ? (\n <ScrollRestoration />\n ) : null}\n </>\n ) : null}\n </ShellComponent>\n )\n}\n\n// On Rendered can't happen above the root layout because it needs to run after\n// the route subtree has committed below the root layout. Keeping it here lets\n// us fire onRendered even after a hydration mismatch above the root layout\n// (like bad head/link tags, which is common).\nfunction OnRendered({ resetKey }: { resetKey: number }) {\n const router = useRouter()\n\n if (isServer ?? router.isServer) {\n return null\n }\n\n // eslint-disable-next-line react-hooks/rules-of-hooks\n const prevHrefRef = React.useRef<string | undefined>(undefined)\n\n // eslint-disable-next-line react-hooks/rules-of-hooks\n useLayoutEffect(() => {\n const currentHref = router.latestLocation.href\n\n if (\n prevHrefRef.current === undefined ||\n prevHrefRef.current !== currentHref\n ) {\n router.emit({\n type: 'onRendered',\n ...getLocationChangeInfo(\n router.stores.location.get(),\n router.stores.resolvedLocation.get(),\n ),\n })\n prevHrefRef.current = currentHref\n }\n }, [router.latestLocation.state.__TSR_key, resetKey, router])\n\n return null\n}\n\nexport const MatchInner = React.memo(function MatchInnerImpl({\n matchId,\n}: {\n matchId: string\n}): any {\n const router = useRouter()\n\n const getMatchPromise = (\n match: {\n id: string\n _nonReactive: {\n displayPendingPromise?: Promise<void>\n minPendingPromise?: Promise<void>\n loadPromise?: Promise<void>\n }\n },\n key: 'displayPendingPromise' | 'minPendingPromise' | 'loadPromise',\n ) => {\n return (\n router.getMatch(match.id)?._nonReactive[key] ?? match._nonReactive[key]\n )\n }\n\n if (isServer ?? router.isServer) {\n const match = router.stores.matchStores.get(matchId)?.get()\n if (!match) {\n if (process.env.NODE_ENV !== 'production') {\n throw new Error(\n `Invariant failed: Could not find match for matchId \"${matchId}\". Please file an issue!`,\n )\n }\n\n invariant()\n }\n\n const routeId = match.routeId as string\n const route = router.routesById[routeId] as AnyRoute\n const remountFn =\n (router.routesById[routeId] as AnyRoute).options.remountDeps ??\n router.options.defaultRemountDeps\n const remountDeps = remountFn?.({\n routeId,\n loaderDeps: match.loaderDeps,\n params: match._strictParams,\n search: match._strictSearch,\n })\n const key = remountDeps ? JSON.stringify(remountDeps) : undefined\n const Comp = route.options.component ?? router.options.defaultComponent\n const out = Comp ? <Comp key={key} /> : <Outlet />\n\n if (match._displayPending) {\n throw getMatchPromise(match, 'displayPendingPromise')\n }\n\n if (match._forcePending) {\n throw getMatchPromise(match, 'minPendingPromise')\n }\n\n if (match.status === 'pending') {\n throw getMatchPromise(match, 'loadPromise')\n }\n\n if (match.status === 'notFound') {\n if (!isNotFound(match.error)) {\n if (process.env.NODE_ENV !== 'production') {\n throw new Error('Invariant failed: Expected a notFound error')\n }\n\n invariant()\n }\n return renderRouteNotFound(router, route, match.error)\n }\n\n if (match.status === 'redirected') {\n if (!isRedirect(match.error)) {\n if (process.env.NODE_ENV !== 'production') {\n throw new Error('Invariant failed: Expected a redirect error')\n }\n\n invariant()\n }\n throw getMatchPromise(match, 'loadPromise')\n }\n\n if (match.status === 'error') {\n const RouteErrorComponent =\n (route.options.errorComponent ??\n router.options.defaultErrorComponent) ||\n ErrorComponent\n return (\n <RouteErrorComponent\n error={match.error as any}\n reset={undefined as any}\n info={{\n componentStack: '',\n }}\n />\n )\n }\n\n return out\n }\n\n const matchStore = router.stores.matchStores.get(matchId)\n if (!matchStore) {\n if (process.env.NODE_ENV !== 'production') {\n throw new Error(\n `Invariant failed: Could not find match for matchId \"${matchId}\". Please file an issue!`,\n )\n }\n\n invariant()\n }\n // eslint-disable-next-line react-hooks/rules-of-hooks\n const match = useStore(matchStore, (value) => value)\n const routeId = match.routeId as string\n const route = router.routesById[routeId] as AnyRoute\n // eslint-disable-next-line react-hooks/rules-of-hooks\n const key = React.useMemo(() => {\n const remountFn =\n (router.routesById[routeId] as AnyRoute).options.remountDeps ??\n router.options.defaultRemountDeps\n const remountDeps = remountFn?.({\n routeId,\n loaderDeps: match.loaderDeps,\n params: match._strictParams,\n search: match._strictSearch,\n })\n return remountDeps ? JSON.stringify(remountDeps) : undefined\n }, [\n routeId,\n match.loaderDeps,\n match._strictParams,\n match._strictSearch,\n router.options.defaultRemountDeps,\n router.routesById,\n ])\n\n // eslint-disable-next-line react-hooks/rules-of-hooks\n const out = React.useMemo(() => {\n const Comp = route.options.component ?? router.options.defaultComponent\n if (Comp) {\n return <Comp key={key} />\n }\n return <Outlet />\n }, [key, route.options.component, router.options.defaultComponent])\n\n if (match._displayPending) {\n throw getMatchPromise(match, 'displayPendingPromise')\n }\n\n if (match._forcePending) {\n throw getMatchPromise(match, 'minPendingPromise')\n }\n\n // see also hydrate() in packages/router-core/src/ssr/ssr-client.ts\n if (match.status === 'pending') {\n // We're pending, and if we have a minPendingMs, we need to wait for it\n const pendingMinMs =\n route.options.pendingMinMs ?? router.options.defaultPendingMinMs\n if (pendingMinMs) {\n const routerMatch = router.getMatch(match.id)\n if (routerMatch && !routerMatch._nonReactive.minPendingPromise) {\n // Create a promise that will resolve after the minPendingMs\n if (!(isServer ?? router.isServer)) {\n const minPendingPromise = createControlledPromise<void>()\n\n routerMatch._nonReactive.minPendingPromise = minPendingPromise\n\n setTimeout(() => {\n minPendingPromise.resolve()\n // We've handled the minPendingPromise, so we can delete it\n routerMatch._nonReactive.minPendingPromise = undefined\n }, pendingMinMs)\n }\n }\n }\n throw getMatchPromise(match, 'loadPromise')\n }\n\n if (match.status === 'notFound') {\n if (!isNotFound(match.error)) {\n if (process.env.NODE_ENV !== 'production') {\n throw new Error('Invariant failed: Expected a notFound error')\n }\n\n invariant()\n }\n return renderRouteNotFound(router, route, match.error)\n }\n\n if (match.status === 'redirected') {\n // A match can be observed as redirected during an in-flight transition,\n // especially when pending UI is already rendering. Suspend on the match's\n // load promise so React can abandon this stale render and continue the\n // redirect transition.\n if (!isRedirect(match.error)) {\n if (process.env.NODE_ENV !== 'production') {\n throw new Error('Invariant failed: Expected a redirect error')\n }\n\n invariant()\n }\n\n throw getMatchPromise(match, 'loadPromise')\n }\n\n if (match.status === 'error') {\n // If we're on the server, we need to use React's new and super\n // wonky api for throwing errors from a server side render inside\n // of a suspense boundary. This is the only way to get\n // renderToPipeableStream to not hang indefinitely.\n // We'll serialize the error and rethrow it on the client.\n if (isServer ?? router.isServer) {\n const RouteErrorComponent =\n (route.options.errorComponent ??\n router.options.defaultErrorComponent) ||\n ErrorComponent\n return (\n <RouteErrorComponent\n error={match.error as any}\n reset={undefined as any}\n info={{\n componentStack: '',\n }}\n />\n )\n }\n\n throw match.error\n }\n\n return out\n})\n\n/**\n * Render the next child match in the route tree. Typically used inside\n * a route component to render nested routes.\n *\n * @link https://tanstack.com/router/latest/docs/framework/react/api/router/outletComponent\n */\nexport const Outlet = React.memo(function OutletImpl() {\n const router = useRouter()\n const matchId = React.useContext(matchContext)\n\n let routeId: string | undefined\n let parentGlobalNotFound = false\n let childMatchId: string | undefined\n\n if (isServer ?? router.isServer) {\n const matches = router.stores.matches.get()\n const parentIndex = matchId\n ? matches.findIndex((match) => match.id === matchId)\n : -1\n const parentMatch = parentIndex >= 0 ? matches[parentIndex] : undefined\n routeId = parentMatch?.routeId as string | undefined\n parentGlobalNotFound = parentMatch?.globalNotFound ?? false\n childMatchId =\n parentIndex >= 0 ? (matches[parentIndex + 1]?.id as string) : undefined\n } else {\n // Subscribe directly to the match store from the pool instead of\n // the two-level byId → matchStore pattern.\n const parentMatchStore = matchId\n ? router.stores.matchStores.get(matchId)\n : undefined\n\n // eslint-disable-next-line react-hooks/rules-of-hooks\n ;[routeId, parentGlobalNotFound] = useStore(parentMatchStore, (match) => [\n match?.routeId as string | undefined,\n match?.globalNotFound ?? false,\n ])\n\n // eslint-disable-next-line react-hooks/rules-of-hooks\n childMatchId = useStore(router.stores.matchesId, (ids) => {\n const index = ids.findIndex((id) => id === matchId)\n return ids[index + 1]\n })\n }\n\n const route = routeId ? router.routesById[routeId] : undefined\n\n const pendingElement = router.options.defaultPendingComponent ? (\n <router.options.defaultPendingComponent />\n ) : null\n\n if (parentGlobalNotFound) {\n if (!route) {\n if (process.env.NODE_ENV !== 'production') {\n throw new Error(\n 'Invariant failed: Could not resolve route for Outlet render',\n )\n }\n\n invariant()\n }\n return renderRouteNotFound(router, route, undefined)\n }\n\n if (!childMatchId) {\n return null\n }\n\n const nextMatch = <Match matchId={childMatchId} />\n\n if (routeId === rootRouteId) {\n return (\n <React.Suspense fallback={pendingElement}>{nextMatch}</React.Suspense>\n )\n }\n\n return nextMatch\n})\n"],"mappings":"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"} | ||
| {"version":3,"file":"Match.js","names":[],"sources":["../../src/Match.tsx"],"sourcesContent":["'use client'\n\nimport * as React from 'react'\nimport { useStore } from '@tanstack/react-store'\nimport {\n createControlledPromise,\n getLocationChangeInfo,\n invariant,\n isNotFound,\n isRedirect,\n rootRouteId,\n} from '@tanstack/router-core'\nimport { isServer } from '@tanstack/router-core/isServer'\nimport { CatchBoundary, ErrorComponent } from './CatchBoundary'\nimport { useRouter } from './useRouter'\nimport { CatchNotFound } from './not-found'\nimport { matchContext } from './matchContext'\nimport { SafeFragment } from './SafeFragment'\nimport { renderRouteNotFound } from './renderRouteNotFound'\nimport { ScrollRestoration } from './scroll-restoration'\nimport { ClientOnly } from './ClientOnly'\nimport { useLayoutEffect } from './utils'\nimport type {\n AnyRoute,\n AnyRouteMatch,\n ParsedLocation,\n RootRouteOptions,\n} from '@tanstack/router-core'\n\ntype OutletMatchSelection = [\n routeId: string | undefined,\n parentGlobalNotFound: boolean,\n]\n\nconst matchViewFieldsEqual = (a: AnyRouteMatch, b: AnyRouteMatch) =>\n a.routeId === b.routeId && a._displayPending === b._displayPending\n\nconst outletMatchSelectionEqual = (\n a: OutletMatchSelection,\n b: OutletMatchSelection,\n) => a[0] === b[0] && a[1] === b[1]\n\nexport const Match = React.memo(function MatchImpl({\n matchId,\n}: {\n matchId: string\n}) {\n const router = useRouter()\n\n if (isServer ?? router.isServer) {\n const match = router.stores.matchStores.get(matchId)?.get()\n if (!match) {\n if (process.env.NODE_ENV !== 'production') {\n throw new Error(\n `Invariant failed: Could not find match for matchId \"${matchId}\". Please file an issue!`,\n )\n }\n\n invariant()\n }\n\n const routeId = match.routeId as string\n const parentRouteId = (router.routesById[routeId] as AnyRoute).parentRoute\n ?.id\n\n return (\n <MatchView\n router={router}\n matchId={matchId}\n resetKey={router.stores.loadedAt.get()}\n matchState={{\n routeId,\n ssr: match.ssr,\n _displayPending: match._displayPending,\n parentRouteId,\n }}\n />\n )\n }\n\n // Subscribe directly to the match store from the pool.\n // The matchId prop is stable for this component's lifetime (set by Outlet),\n // and reconcileMatchPool reuses stores for the same matchId.\n\n const matchStore = router.stores.matchStores.get(matchId)\n if (!matchStore) {\n if (process.env.NODE_ENV !== 'production') {\n throw new Error(\n `Invariant failed: Could not find match for matchId \"${matchId}\". Please file an issue!`,\n )\n }\n\n invariant()\n }\n // eslint-disable-next-line react-hooks/rules-of-hooks\n const resetKey = useStore(router.stores.loadedAt, (loadedAt) => loadedAt)\n // eslint-disable-next-line react-hooks/rules-of-hooks\n const match = useStore(matchStore, (value) => value, matchViewFieldsEqual)\n // eslint-disable-next-line react-hooks/rules-of-hooks\n const matchState = React.useMemo(() => {\n const routeId = match.routeId as string\n const parentRouteId = (router.routesById[routeId] as AnyRoute).parentRoute\n ?.id\n\n return {\n routeId,\n ssr: match.ssr,\n _displayPending: match._displayPending,\n parentRouteId: parentRouteId as string | undefined,\n } satisfies MatchViewState\n }, [match._displayPending, match.routeId, match.ssr, router.routesById])\n\n return (\n <MatchView\n router={router}\n matchId={matchId}\n resetKey={resetKey}\n matchState={matchState}\n />\n )\n})\n\ntype MatchViewState = {\n routeId: string\n ssr: boolean | 'data-only' | undefined\n _displayPending: boolean | undefined\n parentRouteId: string | undefined\n}\n\nfunction MatchView({\n router,\n matchId,\n resetKey,\n matchState,\n}: {\n router: ReturnType<typeof useRouter>\n matchId: string\n resetKey: number\n matchState: MatchViewState\n}) {\n const route: AnyRoute = router.routesById[matchState.routeId]\n\n const PendingComponent =\n route.options.pendingComponent ?? router.options.defaultPendingComponent\n\n const pendingElement = PendingComponent ? <PendingComponent /> : null\n\n const routeErrorComponent =\n route.options.errorComponent ?? router.options.defaultErrorComponent\n\n const routeOnCatch = route.options.onCatch ?? router.options.defaultOnCatch\n\n const routeNotFoundComponent = route.isRoot\n ? // If it's the root route, use the globalNotFound option, with fallback to the notFoundRoute's component\n (route.options.notFoundComponent ??\n router.options.notFoundRoute?.options.component)\n : route.options.notFoundComponent\n\n const resolvedNoSsr =\n matchState.ssr === false || matchState.ssr === 'data-only'\n const ResolvedSuspenseBoundary =\n // If we're on the root route, allow forcefully wrapping in suspense\n (!route.isRoot || route.options.wrapInSuspense || resolvedNoSsr) &&\n (route.options.wrapInSuspense ??\n PendingComponent ??\n ((route.options.errorComponent as any)?.preload || resolvedNoSsr))\n ? React.Suspense\n : SafeFragment\n\n const ResolvedCatchBoundary = routeErrorComponent\n ? CatchBoundary\n : SafeFragment\n\n const ResolvedNotFoundBoundary = routeNotFoundComponent\n ? CatchNotFound\n : SafeFragment\n\n const ShellComponent = route.isRoot\n ? ((route.options as RootRouteOptions).shellComponent ?? SafeFragment)\n : SafeFragment\n return (\n <ShellComponent>\n <matchContext.Provider value={matchId}>\n <ResolvedSuspenseBoundary fallback={pendingElement}>\n <ResolvedCatchBoundary\n getResetKey={() => resetKey}\n errorComponent={routeErrorComponent || ErrorComponent}\n onCatch={(error, errorInfo) => {\n // Forward not found errors (we don't want to show the error component for these)\n if (isNotFound(error)) {\n error.routeId ??= matchState.routeId as any\n throw error\n }\n if (process.env.NODE_ENV !== 'production') {\n console.warn(`Warning: Error in route match: ${matchId}`)\n }\n routeOnCatch?.(error, errorInfo)\n }}\n >\n <ResolvedNotFoundBoundary\n fallback={(error) => {\n error.routeId ??= matchState.routeId as any\n\n // If the current not found handler doesn't exist or it has a\n // route ID which doesn't match the current route, rethrow the error\n if (\n !routeNotFoundComponent ||\n (error.routeId && error.routeId !== matchState.routeId) ||\n (!error.routeId && !route.isRoot)\n )\n throw error\n\n return React.createElement(routeNotFoundComponent, error as any)\n }}\n >\n {resolvedNoSsr || matchState._displayPending ? (\n <ClientOnly fallback={pendingElement}>\n <MatchInner matchId={matchId} />\n </ClientOnly>\n ) : (\n <MatchInner matchId={matchId} />\n )}\n </ResolvedNotFoundBoundary>\n </ResolvedCatchBoundary>\n </ResolvedSuspenseBoundary>\n </matchContext.Provider>\n {matchState.parentRouteId === rootRouteId ? (\n <>\n <OnRendered />\n {router.options.scrollRestoration && (isServer ?? router.isServer) ? (\n <ScrollRestoration />\n ) : null}\n </>\n ) : null}\n </ShellComponent>\n )\n}\n\n// On Rendered can't happen above the root layout because it needs to run after\n// the route subtree has committed below the root layout. Keeping it here lets\n// us fire onRendered even after a hydration mismatch above the root layout\n// (like bad head/link tags, which is common).\nfunction OnRendered() {\n const router = useRouter()\n\n if (isServer ?? router.isServer) {\n return null\n }\n\n // Track the resolvedLocation as of the last render so that onRendered can\n // report the correct fromLocation. By the time this effect fires,\n // resolvedLocation has already been updated to the new location by\n // Transitioner, so we cannot use router.stores.resolvedLocation.get()\n // directly as the fromLocation.\n // @ts-expect-error -- init to `undefined` but don't write `undefined` to shave bytes\n // eslint-disable-next-line react-hooks/rules-of-hooks\n const prevResolvedLocationRef = React.useRef<\n ParsedLocation<any> | undefined\n >()\n // eslint-disable-next-line react-hooks/rules-of-hooks\n const renderedLocationKey = useStore(\n router.stores.resolvedLocation,\n (resolvedLocation) => resolvedLocation?.state.__TSR_key,\n )\n\n // eslint-disable-next-line react-hooks/rules-of-hooks\n useLayoutEffect(() => {\n const currentResolvedLocation = router.stores.resolvedLocation.get()\n const previousResolvedLocation = prevResolvedLocationRef.current\n\n if (\n currentResolvedLocation &&\n (!previousResolvedLocation ||\n previousResolvedLocation.href !== currentResolvedLocation.href)\n ) {\n router.emit({\n type: 'onRendered',\n ...getLocationChangeInfo(\n router.stores.location.get(),\n previousResolvedLocation ?? currentResolvedLocation,\n ),\n })\n }\n prevResolvedLocationRef.current = currentResolvedLocation\n }, [renderedLocationKey, router])\n\n return null\n}\n\nexport const MatchInner = React.memo(function MatchInnerImpl({\n matchId,\n}: {\n matchId: string\n}): any {\n const router = useRouter()\n\n const getMatchPromise = (\n match: {\n id: string\n _nonReactive: {\n displayPendingPromise?: Promise<void>\n minPendingPromise?: Promise<void>\n loadPromise?: Promise<void>\n }\n },\n key: 'displayPendingPromise' | 'minPendingPromise' | 'loadPromise',\n ) => {\n return (\n router.getMatch(match.id)?._nonReactive[key] ?? match._nonReactive[key]\n )\n }\n\n if (isServer ?? router.isServer) {\n const match = router.stores.matchStores.get(matchId)?.get()\n if (!match) {\n if (process.env.NODE_ENV !== 'production') {\n throw new Error(\n `Invariant failed: Could not find match for matchId \"${matchId}\". Please file an issue!`,\n )\n }\n\n invariant()\n }\n\n const routeId = match.routeId as string\n const route = router.routesById[routeId] as AnyRoute\n const remountFn =\n (router.routesById[routeId] as AnyRoute).options.remountDeps ??\n router.options.defaultRemountDeps\n const remountDeps = remountFn?.({\n routeId,\n loaderDeps: match.loaderDeps,\n params: match._strictParams,\n search: match._strictSearch,\n })\n const key = remountDeps ? JSON.stringify(remountDeps) : undefined\n const Comp = route.options.component ?? router.options.defaultComponent\n const out = Comp ? <Comp key={key} /> : <Outlet />\n\n if (match._displayPending) {\n throw getMatchPromise(match, 'displayPendingPromise')\n }\n\n if (match._forcePending) {\n throw getMatchPromise(match, 'minPendingPromise')\n }\n\n if (match.status === 'pending') {\n throw getMatchPromise(match, 'loadPromise')\n }\n\n if (match.status === 'notFound') {\n if (!isNotFound(match.error)) {\n if (process.env.NODE_ENV !== 'production') {\n throw new Error('Invariant failed: Expected a notFound error')\n }\n\n invariant()\n }\n return renderRouteNotFound(router, route, match.error)\n }\n\n if (match.status === 'redirected') {\n if (!isRedirect(match.error)) {\n if (process.env.NODE_ENV !== 'production') {\n throw new Error('Invariant failed: Expected a redirect error')\n }\n\n invariant()\n }\n throw getMatchPromise(match, 'loadPromise')\n }\n\n if (match.status === 'error') {\n const RouteErrorComponent =\n (route.options.errorComponent ??\n router.options.defaultErrorComponent) ||\n ErrorComponent\n return (\n <RouteErrorComponent\n error={match.error as any}\n reset={undefined as any}\n info={{\n componentStack: '',\n }}\n />\n )\n }\n\n return out\n }\n\n const matchStore = router.stores.matchStores.get(matchId)\n if (!matchStore) {\n if (process.env.NODE_ENV !== 'production') {\n throw new Error(\n `Invariant failed: Could not find match for matchId \"${matchId}\". Please file an issue!`,\n )\n }\n\n invariant()\n }\n // eslint-disable-next-line react-hooks/rules-of-hooks\n const match = useStore(matchStore, (value) => value)\n const routeId = match.routeId as string\n const route = router.routesById[routeId] as AnyRoute\n // eslint-disable-next-line react-hooks/rules-of-hooks\n const key = React.useMemo(() => {\n const remountFn =\n (router.routesById[routeId] as AnyRoute).options.remountDeps ??\n router.options.defaultRemountDeps\n const remountDeps = remountFn?.({\n routeId,\n loaderDeps: match.loaderDeps,\n params: match._strictParams,\n search: match._strictSearch,\n })\n return remountDeps ? JSON.stringify(remountDeps) : undefined\n }, [\n routeId,\n match.loaderDeps,\n match._strictParams,\n match._strictSearch,\n router.options.defaultRemountDeps,\n router.routesById,\n ])\n\n // eslint-disable-next-line react-hooks/rules-of-hooks\n const out = React.useMemo(() => {\n const Comp = route.options.component ?? router.options.defaultComponent\n if (Comp) {\n return <Comp key={key} />\n }\n return <Outlet />\n }, [key, route.options.component, router.options.defaultComponent])\n\n if (match._displayPending) {\n throw getMatchPromise(match, 'displayPendingPromise')\n }\n\n if (match._forcePending) {\n throw getMatchPromise(match, 'minPendingPromise')\n }\n\n // see also hydrate() in packages/router-core/src/ssr/ssr-client.ts\n if (match.status === 'pending') {\n // We're pending, and if we have a minPendingMs, we need to wait for it\n const pendingMinMs =\n route.options.pendingMinMs ?? router.options.defaultPendingMinMs\n if (pendingMinMs) {\n const routerMatch = router.getMatch(match.id)\n if (routerMatch && !routerMatch._nonReactive.minPendingPromise) {\n // Create a promise that will resolve after the minPendingMs\n if (!(isServer ?? router.isServer)) {\n const minPendingPromise = createControlledPromise<void>()\n\n routerMatch._nonReactive.minPendingPromise = minPendingPromise\n\n setTimeout(() => {\n minPendingPromise.resolve()\n // We've handled the minPendingPromise, so we can delete it\n routerMatch._nonReactive.minPendingPromise = undefined\n }, pendingMinMs)\n }\n }\n }\n throw getMatchPromise(match, 'loadPromise')\n }\n\n if (match.status === 'notFound') {\n if (!isNotFound(match.error)) {\n if (process.env.NODE_ENV !== 'production') {\n throw new Error('Invariant failed: Expected a notFound error')\n }\n\n invariant()\n }\n return renderRouteNotFound(router, route, match.error)\n }\n\n if (match.status === 'redirected') {\n // A match can be observed as redirected during an in-flight transition,\n // especially when pending UI is already rendering. Suspend on the match's\n // load promise so React can abandon this stale render and continue the\n // redirect transition.\n if (!isRedirect(match.error)) {\n if (process.env.NODE_ENV !== 'production') {\n throw new Error('Invariant failed: Expected a redirect error')\n }\n\n invariant()\n }\n\n throw getMatchPromise(match, 'loadPromise')\n }\n\n if (match.status === 'error') {\n // If we're on the server, we need to use React's new and super\n // wonky api for throwing errors from a server side render inside\n // of a suspense boundary. This is the only way to get\n // renderToPipeableStream to not hang indefinitely.\n // We'll serialize the error and rethrow it on the client.\n if (isServer ?? router.isServer) {\n const RouteErrorComponent =\n (route.options.errorComponent ??\n router.options.defaultErrorComponent) ||\n ErrorComponent\n return (\n <RouteErrorComponent\n error={match.error as any}\n reset={undefined as any}\n info={{\n componentStack: '',\n }}\n />\n )\n }\n\n throw match.error\n }\n\n return out\n})\n\n/**\n * Render the next child match in the route tree. Typically used inside\n * a route component to render nested routes.\n *\n * @link https://tanstack.com/router/latest/docs/framework/react/api/router/outletComponent\n */\nexport const Outlet = React.memo(function OutletImpl() {\n const router = useRouter()\n const matchId = React.useContext(matchContext)\n\n let routeId: string | undefined\n let parentGlobalNotFound = false\n let childMatchId: string | undefined\n\n if (isServer ?? router.isServer) {\n const matches = router.stores.matches.get()\n const parentIndex = matchId\n ? matches.findIndex((match) => match.id === matchId)\n : -1\n const parentMatch = parentIndex >= 0 ? matches[parentIndex] : undefined\n routeId = parentMatch?.routeId as string | undefined\n parentGlobalNotFound = parentMatch?.globalNotFound ?? false\n childMatchId =\n parentIndex >= 0 ? (matches[parentIndex + 1]?.id as string) : undefined\n } else {\n // Subscribe directly to the match store from the pool instead of\n // the two-level byId → matchStore pattern.\n const parentMatchStore = matchId\n ? router.stores.matchStores.get(matchId)\n : undefined\n\n // eslint-disable-next-line react-hooks/rules-of-hooks\n ;[routeId, parentGlobalNotFound] = useStore(\n parentMatchStore,\n (match): OutletMatchSelection => [\n match?.routeId as string | undefined,\n match?.globalNotFound ?? false,\n ],\n outletMatchSelectionEqual,\n )\n\n // eslint-disable-next-line react-hooks/rules-of-hooks\n childMatchId = useStore(router.stores.matchesId, (ids) => {\n const index = ids.findIndex((id) => id === matchId)\n return ids[index + 1]\n })\n }\n\n const route = routeId ? router.routesById[routeId] : undefined\n\n const pendingElement = router.options.defaultPendingComponent ? (\n <router.options.defaultPendingComponent />\n ) : null\n\n if (parentGlobalNotFound) {\n if (!route) {\n if (process.env.NODE_ENV !== 'production') {\n throw new Error(\n 'Invariant failed: Could not resolve route for Outlet render',\n )\n }\n\n invariant()\n }\n return renderRouteNotFound(router, route, undefined)\n }\n\n if (!childMatchId) {\n return null\n }\n\n const nextMatch = <Match matchId={childMatchId} />\n\n if (routeId === rootRouteId) {\n return (\n <React.Suspense fallback={pendingElement}>{nextMatch}</React.Suspense>\n )\n }\n\n return nextMatch\n})\n"],"mappings":"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"} |
+3
-11
@@ -5,6 +5,7 @@ "use client"; | ||
| import { useRouter } from "./useRouter.js"; | ||
| import { useStructuralSharing } from "./useMatch.js"; | ||
| import { Transitioner } from "./Transitioner.js"; | ||
| import { SafeFragment } from "./SafeFragment.js"; | ||
| import { Match } from "./Match.js"; | ||
| import { replaceEqualDeep, rootRouteId } from "@tanstack/router-core"; | ||
| import { rootRouteId } from "@tanstack/router-core"; | ||
| import * as React$1 from "react"; | ||
@@ -87,3 +88,2 @@ import { jsx, jsxs } from "react/jsx-runtime"; | ||
| const router = useRouter(); | ||
| const previousResult = React$1.useRef(void 0); | ||
| if (isServer ?? router.isServer) { | ||
@@ -93,11 +93,3 @@ const matches = router.stores.matches.get(); | ||
| } | ||
| return useStore(router.stores.matches, (matches) => { | ||
| const selected = opts?.select ? opts.select(matches) : matches; | ||
| if (opts?.structuralSharing ?? router.options.defaultStructuralSharing) { | ||
| const shared = replaceEqualDeep(previousResult.current, selected); | ||
| previousResult.current = shared; | ||
| return shared; | ||
| } | ||
| return selected; | ||
| }); | ||
| return useStore(router.stores.matches, useStructuralSharing(opts, router)); | ||
| } | ||
@@ -104,0 +96,0 @@ /** |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"Matches.js","names":[],"sources":["../../src/Matches.tsx"],"sourcesContent":["'use client'\n\nimport * as React from 'react'\nimport { useStore } from '@tanstack/react-store'\nimport { replaceEqualDeep, rootRouteId } from '@tanstack/router-core'\nimport { isServer } from '@tanstack/router-core/isServer'\nimport { CatchBoundary, ErrorComponent } from './CatchBoundary'\nimport { useRouter } from './useRouter'\nimport { Transitioner } from './Transitioner'\nimport { matchContext } from './matchContext'\nimport { Match } from './Match'\nimport { SafeFragment } from './SafeFragment'\nimport type {\n StructuralSharingOption,\n ValidateSelected,\n} from './structuralSharing'\nimport type {\n AnyRoute,\n AnyRouter,\n DeepPartial,\n Expand,\n MakeOptionalPathParams,\n MakeOptionalSearchParams,\n MakeRouteMatchUnion,\n MaskOptions,\n MatchRouteOptions,\n RegisteredRouter,\n ResolveRoute,\n ToSubOptionsProps,\n} from '@tanstack/router-core'\n\ndeclare module '@tanstack/router-core' {\n export interface RouteMatchExtensions {\n meta?: Array<React.JSX.IntrinsicElements['meta'] | undefined>\n links?: Array<React.JSX.IntrinsicElements['link'] | undefined>\n scripts?: Array<React.JSX.IntrinsicElements['script'] | undefined>\n styles?: Array<React.JSX.IntrinsicElements['style'] | undefined>\n headScripts?: Array<React.JSX.IntrinsicElements['script'] | undefined>\n }\n}\n\n/**\n * Internal component that renders the router's active match tree with\n * suspense, error, and not-found boundaries. Rendered by `RouterProvider`.\n */\nexport function Matches() {\n const router = useRouter()\n const rootRoute: AnyRoute = router.routesById[rootRouteId]\n\n const PendingComponent =\n rootRoute.options.pendingComponent ?? router.options.defaultPendingComponent\n\n const pendingElement = PendingComponent ? <PendingComponent /> : null\n\n // Do not render a root Suspense during SSR or hydrating from SSR\n const ResolvedSuspense =\n (isServer ?? router.isServer) ||\n (typeof document !== 'undefined' && router.ssr)\n ? SafeFragment\n : React.Suspense\n\n const inner = (\n <ResolvedSuspense fallback={pendingElement}>\n {!(isServer ?? router.isServer) && <Transitioner />}\n <MatchesInner />\n </ResolvedSuspense>\n )\n\n return router.options.InnerWrap ? (\n <router.options.InnerWrap>{inner}</router.options.InnerWrap>\n ) : (\n inner\n )\n}\n\nfunction MatchesInner() {\n const router = useRouter()\n const _isServer = isServer ?? router.isServer\n const matchId = _isServer\n ? router.stores.firstId.get()\n : // eslint-disable-next-line react-hooks/rules-of-hooks\n useStore(router.stores.firstId, (id) => id)\n const resetKey = _isServer\n ? router.stores.loadedAt.get()\n : // eslint-disable-next-line react-hooks/rules-of-hooks\n useStore(router.stores.loadedAt, (loadedAt) => loadedAt)\n\n const matchComponent = matchId ? <Match matchId={matchId} /> : null\n\n return (\n <matchContext.Provider value={matchId}>\n {router.options.disableGlobalCatchBoundary ? (\n matchComponent\n ) : (\n <CatchBoundary\n getResetKey={() => resetKey}\n errorComponent={ErrorComponent}\n onCatch={\n process.env.NODE_ENV !== 'production'\n ? (error) => {\n console.warn(\n `Warning: The following error wasn't caught by any route! At the very least, consider setting an 'errorComponent' in your RootRoute!`,\n )\n console.warn(`Warning: ${error.message || error.toString()}`)\n }\n : undefined\n }\n >\n {matchComponent}\n </CatchBoundary>\n )}\n </matchContext.Provider>\n )\n}\n\nexport type UseMatchRouteOptions<\n TRouter extends AnyRouter = RegisteredRouter,\n TFrom extends string = string,\n TTo extends string | undefined = undefined,\n TMaskFrom extends string = TFrom,\n TMaskTo extends string = '',\n> = ToSubOptionsProps<TRouter, TFrom, TTo> &\n DeepPartial<MakeOptionalSearchParams<TRouter, TFrom, TTo>> &\n DeepPartial<MakeOptionalPathParams<TRouter, TFrom, TTo>> &\n MaskOptions<TRouter, TMaskFrom, TMaskTo> &\n MatchRouteOptions\n\n/**\n * Create a matcher function for testing locations against route definitions.\n *\n * The returned function accepts standard navigation options (`to`, `params`,\n * `search`, etc.) and returns either `false` (no match) or the matched params\n * object when the route matches the current or pending location.\n *\n * Useful for conditional rendering and active UI states.\n *\n * @returns A `matchRoute(options)` function that returns `false` or params.\n * @link https://tanstack.com/router/latest/docs/framework/react/api/router/useMatchRouteHook\n */\nexport function useMatchRoute<TRouter extends AnyRouter = RegisteredRouter>() {\n const router = useRouter()\n\n if (!(isServer ?? router.isServer)) {\n // eslint-disable-next-line react-hooks/rules-of-hooks\n useStore(router.stores.matchRouteDeps, (d) => d)\n }\n\n return React.useCallback(\n <\n const TFrom extends string = string,\n const TTo extends string | undefined = undefined,\n const TMaskFrom extends string = TFrom,\n const TMaskTo extends string = '',\n >(\n opts: UseMatchRouteOptions<TRouter, TFrom, TTo, TMaskFrom, TMaskTo>,\n ):\n | false\n | Expand<ResolveRoute<TRouter, TFrom, TTo>['types']['allParams']> => {\n const { pending, caseSensitive, fuzzy, includeSearch, ...rest } = opts\n\n return router.matchRoute(rest as any, {\n pending,\n caseSensitive,\n fuzzy,\n includeSearch,\n })\n },\n [router],\n )\n}\n\nexport type MakeMatchRouteOptions<\n TRouter extends AnyRouter = RegisteredRouter,\n TFrom extends string = string,\n TTo extends string | undefined = undefined,\n TMaskFrom extends string = TFrom,\n TMaskTo extends string = '',\n> = UseMatchRouteOptions<TRouter, TFrom, TTo, TMaskFrom, TMaskTo> & {\n // If a function is passed as a child, it will be given the `isActive` boolean to aid in further styling on the element it returns\n children?:\n | ((\n params?: Expand<\n ResolveRoute<TRouter, TFrom, TTo>['types']['allParams']\n >,\n ) => React.ReactNode)\n | React.ReactNode\n}\n\n/**\n * Component that conditionally renders its children based on whether a route\n * matches the provided `from`/`to` options. If `children` is a function, it\n * receives the matched params object.\n *\n * @link https://tanstack.com/router/latest/docs/framework/react/api/router/matchRouteComponent\n */\nexport function MatchRoute<\n TRouter extends AnyRouter = RegisteredRouter,\n const TFrom extends string = string,\n const TTo extends string | undefined = undefined,\n const TMaskFrom extends string = TFrom,\n const TMaskTo extends string = '',\n>(props: MakeMatchRouteOptions<TRouter, TFrom, TTo, TMaskFrom, TMaskTo>): any {\n const matchRoute = useMatchRoute()\n const params = matchRoute(props as any) as boolean\n\n if (typeof props.children === 'function') {\n return (props.children as any)(params)\n }\n\n return params ? props.children : null\n}\n\nexport interface UseMatchesBaseOptions<\n TRouter extends AnyRouter,\n TSelected,\n TStructuralSharing,\n> {\n select?: (\n matches: Array<MakeRouteMatchUnion<TRouter>>,\n ) => ValidateSelected<TRouter, TSelected, TStructuralSharing>\n}\n\nexport type UseMatchesResult<\n TRouter extends AnyRouter,\n TSelected,\n> = unknown extends TSelected ? Array<MakeRouteMatchUnion<TRouter>> : TSelected\n\nexport function useMatches<\n TRouter extends AnyRouter = RegisteredRouter,\n TSelected = unknown,\n TStructuralSharing extends boolean = boolean,\n>(\n opts?: UseMatchesBaseOptions<TRouter, TSelected, TStructuralSharing> &\n StructuralSharingOption<TRouter, TSelected, TStructuralSharing>,\n): UseMatchesResult<TRouter, TSelected> {\n const router = useRouter<TRouter>()\n const previousResult =\n React.useRef<ValidateSelected<TRouter, TSelected, TStructuralSharing>>(\n undefined,\n )\n\n if (isServer ?? router.isServer) {\n const matches = router.stores.matches.get() as Array<\n MakeRouteMatchUnion<TRouter>\n >\n return (opts?.select ? opts.select(matches) : matches) as UseMatchesResult<\n TRouter,\n TSelected\n >\n }\n\n // eslint-disable-next-line react-hooks/rules-of-hooks\n return useStore(router.stores.matches, (matches) => {\n const selected = opts?.select\n ? opts.select(matches as Array<MakeRouteMatchUnion<TRouter>>)\n : (matches as any)\n\n if (opts?.structuralSharing ?? router.options.defaultStructuralSharing) {\n const shared = replaceEqualDeep(previousResult.current, selected)\n previousResult.current = shared\n return shared\n }\n\n return selected\n }) as UseMatchesResult<TRouter, TSelected>\n}\n\n/**\n * Read the full array of active route matches or select a derived subset.\n *\n * Useful for debugging, breadcrumbs, or aggregating metadata across matches.\n *\n * @returns The array of matches (or the selected value).\n * @link https://tanstack.com/router/latest/docs/framework/react/api/router/useMatchesHook\n */\n\n/**\n * Read the full array of active route matches or select a derived subset.\n *\n * Useful for debugging, breadcrumbs, or aggregating metadata across matches.\n *\n * @link https://tanstack.com/router/latest/docs/framework/react/api/router/useMatchesHook\n */\nexport function useParentMatches<\n TRouter extends AnyRouter = RegisteredRouter,\n TSelected = unknown,\n TStructuralSharing extends boolean = boolean,\n>(\n opts?: UseMatchesBaseOptions<TRouter, TSelected, TStructuralSharing> &\n StructuralSharingOption<TRouter, TSelected, TStructuralSharing>,\n): UseMatchesResult<TRouter, TSelected> {\n const contextMatchId = React.useContext(matchContext)\n\n return useMatches({\n select: (matches: Array<MakeRouteMatchUnion<TRouter>>) => {\n matches = matches.slice(\n 0,\n matches.findIndex((d) => d.id === contextMatchId),\n )\n return opts?.select ? opts.select(matches) : matches\n },\n structuralSharing: opts?.structuralSharing,\n } as any)\n}\n\n/**\n * Read the array of active route matches that are children of the current\n * match (or selected parent) in the match tree.\n */\nexport function useChildMatches<\n TRouter extends AnyRouter = RegisteredRouter,\n TSelected = unknown,\n TStructuralSharing extends boolean = boolean,\n>(\n opts?: UseMatchesBaseOptions<TRouter, TSelected, TStructuralSharing> &\n StructuralSharingOption<TRouter, TSelected, TStructuralSharing>,\n): UseMatchesResult<TRouter, TSelected> {\n const contextMatchId = React.useContext(matchContext)\n\n return useMatches({\n select: (matches: Array<MakeRouteMatchUnion<TRouter>>) => {\n matches = matches.slice(\n matches.findIndex((d) => d.id === contextMatchId) + 1,\n )\n return opts?.select ? opts.select(matches) : matches\n },\n structuralSharing: opts?.structuralSharing,\n } as any)\n}\n"],"mappings":"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"} | ||
| {"version":3,"file":"Matches.js","names":[],"sources":["../../src/Matches.tsx"],"sourcesContent":["'use client'\n\nimport * as React from 'react'\nimport { useStore } from '@tanstack/react-store'\nimport { rootRouteId } from '@tanstack/router-core'\nimport { isServer } from '@tanstack/router-core/isServer'\nimport { CatchBoundary, ErrorComponent } from './CatchBoundary'\nimport { useRouter } from './useRouter'\nimport { useStructuralSharing } from './useMatch'\nimport { Transitioner } from './Transitioner'\nimport { matchContext } from './matchContext'\nimport { Match } from './Match'\nimport { SafeFragment } from './SafeFragment'\nimport type {\n StructuralSharingOption,\n ValidateSelected,\n} from './structuralSharing'\nimport type {\n AnyRoute,\n AnyRouter,\n DeepPartial,\n Expand,\n MakeOptionalPathParams,\n MakeOptionalSearchParams,\n MakeRouteMatchUnion,\n MaskOptions,\n MatchRouteOptions,\n RegisteredRouter,\n ResolveRoute,\n ToSubOptionsProps,\n} from '@tanstack/router-core'\n\ndeclare module '@tanstack/router-core' {\n export interface RouteMatchExtensions {\n meta?: Array<React.JSX.IntrinsicElements['meta'] | undefined>\n links?: Array<React.JSX.IntrinsicElements['link'] | undefined>\n scripts?: Array<React.JSX.IntrinsicElements['script'] | undefined>\n styles?: Array<React.JSX.IntrinsicElements['style'] | undefined>\n headScripts?: Array<React.JSX.IntrinsicElements['script'] | undefined>\n }\n}\n\n/**\n * Internal component that renders the router's active match tree with\n * suspense, error, and not-found boundaries. Rendered by `RouterProvider`.\n */\nexport function Matches() {\n const router = useRouter()\n const rootRoute: AnyRoute = router.routesById[rootRouteId]\n\n const PendingComponent =\n rootRoute.options.pendingComponent ?? router.options.defaultPendingComponent\n\n const pendingElement = PendingComponent ? <PendingComponent /> : null\n\n // Do not render a root Suspense during SSR or hydrating from SSR\n const ResolvedSuspense =\n (isServer ?? router.isServer) ||\n (typeof document !== 'undefined' && router.ssr)\n ? SafeFragment\n : React.Suspense\n\n const inner = (\n <ResolvedSuspense fallback={pendingElement}>\n {!(isServer ?? router.isServer) && <Transitioner />}\n <MatchesInner />\n </ResolvedSuspense>\n )\n\n return router.options.InnerWrap ? (\n <router.options.InnerWrap>{inner}</router.options.InnerWrap>\n ) : (\n inner\n )\n}\n\nfunction MatchesInner() {\n const router = useRouter()\n const _isServer = isServer ?? router.isServer\n const matchId = _isServer\n ? router.stores.firstId.get()\n : // eslint-disable-next-line react-hooks/rules-of-hooks\n useStore(router.stores.firstId, (id) => id)\n const resetKey = _isServer\n ? router.stores.loadedAt.get()\n : // eslint-disable-next-line react-hooks/rules-of-hooks\n useStore(router.stores.loadedAt, (loadedAt) => loadedAt)\n\n const matchComponent = matchId ? <Match matchId={matchId} /> : null\n\n return (\n <matchContext.Provider value={matchId}>\n {router.options.disableGlobalCatchBoundary ? (\n matchComponent\n ) : (\n <CatchBoundary\n getResetKey={() => resetKey}\n errorComponent={ErrorComponent}\n onCatch={\n process.env.NODE_ENV !== 'production'\n ? (error) => {\n console.warn(\n `Warning: The following error wasn't caught by any route! At the very least, consider setting an 'errorComponent' in your RootRoute!`,\n )\n console.warn(`Warning: ${error.message || error.toString()}`)\n }\n : undefined\n }\n >\n {matchComponent}\n </CatchBoundary>\n )}\n </matchContext.Provider>\n )\n}\n\nexport type UseMatchRouteOptions<\n TRouter extends AnyRouter = RegisteredRouter,\n TFrom extends string = string,\n TTo extends string | undefined = undefined,\n TMaskFrom extends string = TFrom,\n TMaskTo extends string = '',\n> = ToSubOptionsProps<TRouter, TFrom, TTo> &\n DeepPartial<MakeOptionalSearchParams<TRouter, TFrom, TTo>> &\n DeepPartial<MakeOptionalPathParams<TRouter, TFrom, TTo>> &\n MaskOptions<TRouter, TMaskFrom, TMaskTo> &\n MatchRouteOptions\n\n/**\n * Create a matcher function for testing locations against route definitions.\n *\n * The returned function accepts standard navigation options (`to`, `params`,\n * `search`, etc.) and returns either `false` (no match) or the matched params\n * object when the route matches the current or pending location.\n *\n * Useful for conditional rendering and active UI states.\n *\n * @returns A `matchRoute(options)` function that returns `false` or params.\n * @link https://tanstack.com/router/latest/docs/framework/react/api/router/useMatchRouteHook\n */\nexport function useMatchRoute<TRouter extends AnyRouter = RegisteredRouter>() {\n const router = useRouter()\n\n if (!(isServer ?? router.isServer)) {\n // eslint-disable-next-line react-hooks/rules-of-hooks\n useStore(router.stores.matchRouteDeps, (d) => d)\n }\n\n return React.useCallback(\n <\n const TFrom extends string = string,\n const TTo extends string | undefined = undefined,\n const TMaskFrom extends string = TFrom,\n const TMaskTo extends string = '',\n >(\n opts: UseMatchRouteOptions<TRouter, TFrom, TTo, TMaskFrom, TMaskTo>,\n ):\n | false\n | Expand<ResolveRoute<TRouter, TFrom, TTo>['types']['allParams']> => {\n const { pending, caseSensitive, fuzzy, includeSearch, ...rest } = opts\n\n return router.matchRoute(rest as any, {\n pending,\n caseSensitive,\n fuzzy,\n includeSearch,\n })\n },\n [router],\n )\n}\n\nexport type MakeMatchRouteOptions<\n TRouter extends AnyRouter = RegisteredRouter,\n TFrom extends string = string,\n TTo extends string | undefined = undefined,\n TMaskFrom extends string = TFrom,\n TMaskTo extends string = '',\n> = UseMatchRouteOptions<TRouter, TFrom, TTo, TMaskFrom, TMaskTo> & {\n // If a function is passed as a child, it will be given the `isActive` boolean to aid in further styling on the element it returns\n children?:\n | ((\n params?: Expand<\n ResolveRoute<TRouter, TFrom, TTo>['types']['allParams']\n >,\n ) => React.ReactNode)\n | React.ReactNode\n}\n\n/**\n * Component that conditionally renders its children based on whether a route\n * matches the provided `from`/`to` options. If `children` is a function, it\n * receives the matched params object.\n *\n * @link https://tanstack.com/router/latest/docs/framework/react/api/router/matchRouteComponent\n */\nexport function MatchRoute<\n TRouter extends AnyRouter = RegisteredRouter,\n const TFrom extends string = string,\n const TTo extends string | undefined = undefined,\n const TMaskFrom extends string = TFrom,\n const TMaskTo extends string = '',\n>(props: MakeMatchRouteOptions<TRouter, TFrom, TTo, TMaskFrom, TMaskTo>): any {\n const matchRoute = useMatchRoute()\n const params = matchRoute(props as any) as boolean\n\n if (typeof props.children === 'function') {\n return (props.children as any)(params)\n }\n\n return params ? props.children : null\n}\n\nexport interface UseMatchesBaseOptions<\n TRouter extends AnyRouter,\n TSelected,\n TStructuralSharing,\n> {\n select?: (\n matches: Array<MakeRouteMatchUnion<TRouter>>,\n ) => ValidateSelected<TRouter, TSelected, TStructuralSharing>\n}\n\nexport type UseMatchesResult<\n TRouter extends AnyRouter,\n TSelected,\n> = unknown extends TSelected ? Array<MakeRouteMatchUnion<TRouter>> : TSelected\n\nexport function useMatches<\n TRouter extends AnyRouter = RegisteredRouter,\n TSelected = unknown,\n TStructuralSharing extends boolean = boolean,\n>(\n opts?: UseMatchesBaseOptions<TRouter, TSelected, TStructuralSharing> &\n StructuralSharingOption<TRouter, TSelected, TStructuralSharing>,\n): UseMatchesResult<TRouter, TSelected> {\n const router = useRouter<TRouter>()\n\n if (isServer ?? router.isServer) {\n const matches = router.stores.matches.get() as Array<\n MakeRouteMatchUnion<TRouter>\n >\n return (opts?.select ? opts.select(matches) : matches) as UseMatchesResult<\n TRouter,\n TSelected\n >\n }\n\n // eslint-disable-next-line react-hooks/rules-of-hooks -- condition is static\n return useStore(\n router.stores.matches,\n // eslint-disable-next-line react-hooks/rules-of-hooks -- condition is static\n useStructuralSharing(opts, router),\n ) as UseMatchesResult<TRouter, TSelected>\n}\n\n/**\n * Read the full array of active route matches or select a derived subset.\n *\n * Useful for debugging, breadcrumbs, or aggregating metadata across matches.\n *\n * @returns The array of matches (or the selected value).\n * @link https://tanstack.com/router/latest/docs/framework/react/api/router/useMatchesHook\n */\n\n/**\n * Read the full array of active route matches or select a derived subset.\n *\n * Useful for debugging, breadcrumbs, or aggregating metadata across matches.\n *\n * @link https://tanstack.com/router/latest/docs/framework/react/api/router/useMatchesHook\n */\nexport function useParentMatches<\n TRouter extends AnyRouter = RegisteredRouter,\n TSelected = unknown,\n TStructuralSharing extends boolean = boolean,\n>(\n opts?: UseMatchesBaseOptions<TRouter, TSelected, TStructuralSharing> &\n StructuralSharingOption<TRouter, TSelected, TStructuralSharing>,\n): UseMatchesResult<TRouter, TSelected> {\n const contextMatchId = React.useContext(matchContext)\n\n return useMatches({\n select: (matches: Array<MakeRouteMatchUnion<TRouter>>) => {\n matches = matches.slice(\n 0,\n matches.findIndex((d) => d.id === contextMatchId),\n )\n return opts?.select ? opts.select(matches) : matches\n },\n structuralSharing: opts?.structuralSharing,\n } as any)\n}\n\n/**\n * Read the array of active route matches that are children of the current\n * match (or selected parent) in the match tree.\n */\nexport function useChildMatches<\n TRouter extends AnyRouter = RegisteredRouter,\n TSelected = unknown,\n TStructuralSharing extends boolean = boolean,\n>(\n opts?: UseMatchesBaseOptions<TRouter, TSelected, TStructuralSharing> &\n StructuralSharingOption<TRouter, TSelected, TStructuralSharing>,\n): UseMatchesResult<TRouter, TSelected> {\n const contextMatchId = React.useContext(matchContext)\n\n return useMatches({\n select: (matches: Array<MakeRouteMatchUnion<TRouter>>) => {\n matches = matches.slice(\n matches.findIndex((d) => d.id === contextMatchId) + 1,\n )\n return opts?.select ? opts.select(matches) : matches\n },\n structuralSharing: opts?.structuralSharing,\n } as any)\n}\n"],"mappings":"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"} |
@@ -20,2 +20,3 @@ import { createSsrStreamResponse, transformPipeableStreamWithRouter, transformReadableStreamWithRouter } from "@tanstack/router-core/ssr/server"; | ||
| } | ||
| var isAbortError = (request, error) => request.signal.aborted && error === request.signal.reason || error instanceof Error && error.name === "AbortError"; | ||
| var renderRouterToStream = async ({ request, router, responseHeaders, children }) => { | ||
@@ -26,3 +27,6 @@ if (typeof ReactDOMServer.renderToReadableStream === "function") { | ||
| nonce: router.options.ssr?.nonce, | ||
| progressiveChunkSize: Number.POSITIVE_INFINITY | ||
| progressiveChunkSize: Number.POSITIVE_INFINITY, | ||
| onError: (error, info) => { | ||
| if (!isAbortError(request, error)) console.error("Error in renderToReadableStream:", error, info); | ||
| } | ||
| }); | ||
@@ -79,3 +83,3 @@ if (isbot(request.headers.get("User-Agent"))) await waitForReadyOrAbort(stream.allReady, request.signal); | ||
| onError: (error, info) => { | ||
| console.error("Error in renderToPipeableStream:", error, info); | ||
| if (!isAbortError(request, error)) console.error("Error in renderToPipeableStream:", error, info); | ||
| abortPipeable(error, { defaultError: true }); | ||
@@ -82,0 +86,0 @@ } |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"renderRouterToStream.js","names":[],"sources":["../../../src/ssr/renderRouterToStream.tsx"],"sourcesContent":["import { PassThrough } from 'node:stream'\nimport ReactDOMServer from 'react-dom/server'\nimport { isbot } from 'isbot'\nimport {\n createSsrStreamResponse,\n transformPipeableStreamWithRouter,\n transformReadableStreamWithRouter,\n} from '@tanstack/router-core/ssr/server'\nimport type { AnyRouter } from '@tanstack/router-core'\nimport type { ReadableStream } from 'node:stream/web'\nimport type { ReactNode } from 'react'\n\nconst noop = () => {}\n\n// Bot responses wait for `allReady` so crawlers receive complete HTML.\n// If the request disconnects during that wait, React may not settle quickly;\n// unblock the wait so the response pipeline can abort and clean up.\nasync function waitForReadyOrAbort(\n ready: Promise<unknown>,\n signal: AbortSignal,\n) {\n let cleanup = noop\n try {\n await Promise.race([\n ready,\n new Promise<void>((resolve) => {\n const onAbort = () => resolve()\n cleanup = () => signal.removeEventListener('abort', onAbort)\n signal.addEventListener('abort', onAbort, { once: true })\n if (signal.aborted) resolve()\n }),\n ])\n } finally {\n cleanup()\n }\n}\n\nexport const renderRouterToStream = async ({\n request,\n router,\n responseHeaders,\n children,\n}: {\n request: Request\n router: AnyRouter\n responseHeaders: Headers\n children: ReactNode\n}) => {\n if (typeof ReactDOMServer.renderToReadableStream === 'function') {\n const stream = await ReactDOMServer.renderToReadableStream(children, {\n signal: request.signal,\n nonce: router.options.ssr?.nonce,\n progressiveChunkSize: Number.POSITIVE_INFINITY,\n })\n\n if (isbot(request.headers.get('User-Agent'))) {\n await waitForReadyOrAbort(stream.allReady, request.signal)\n }\n\n const responseStream = transformReadableStreamWithRouter(\n router,\n stream as unknown as ReadableStream,\n { onAbort: () => stream.cancel().catch(() => {}) },\n )\n return createSsrStreamResponse(\n router,\n new Response(responseStream as any, {\n status: router.stores.statusCode.get(),\n headers: responseHeaders,\n }),\n )\n }\n\n if (typeof ReactDOMServer.renderToPipeableStream === 'function') {\n const reactAppPassthrough = new PassThrough()\n\n let pipeable:\n | ReturnType<typeof ReactDOMServer.renderToPipeableStream>\n | undefined\n let responseAttached = false\n let aborted = false\n let endedBeforeAttach = false\n let pendingAbortReason: unknown\n const toError = (reason: unknown) =>\n reason instanceof Error\n ? reason\n : new Error(String(reason ?? 'SSR aborted'))\n const destroyError = (reason: unknown) =>\n reason === undefined ? undefined : toError(reason)\n const pendingDestroyError = () =>\n pendingAbortReason === undefined\n ? toError(pendingAbortReason)\n : destroyError(pendingAbortReason)\n const finishPassThrough = (\n reason: unknown,\n opts?: { defaultError?: boolean },\n ) => {\n if (reactAppPassthrough.destroyed) return\n if (responseAttached) {\n reactAppPassthrough.destroy(\n opts?.defaultError ? toError(reason) : destroyError(reason),\n )\n } else {\n endedBeforeAttach = true\n // onError can fire synchronously before React returns the pipeable\n // handle and before Readable.toWeb() is attached. Defer touching the\n // PassThrough until after the router transform can observe the error.\n }\n }\n const abortPipeable = (\n reason?: unknown,\n opts?: { defaultError?: boolean },\n ) => {\n if (aborted) return\n aborted = true\n pendingAbortReason = reason\n const err = toError(reason)\n try {\n pipeable?.abort(err)\n } catch {\n // ignore — React may throw if already aborted/finished\n }\n finishPassThrough(reason, opts)\n }\n\n // Register before attaching the router transform; the transform may\n // synchronously cleanup/error, and cleanup must still remove this listener.\n if (request.signal.aborted) {\n abortPipeable(request.signal.reason)\n } else {\n const onRequestAbort = () => abortPipeable(request.signal.reason)\n request.signal.addEventListener('abort', onRequestAbort, { once: true })\n router.serverSsr?.onCleanup(() => {\n request.signal.removeEventListener('abort', onRequestAbort)\n })\n }\n\n try {\n pipeable = ReactDOMServer.renderToPipeableStream(children, {\n nonce: router.options.ssr?.nonce,\n progressiveChunkSize: Number.POSITIVE_INFINITY,\n ...(isbot(request.headers.get('User-Agent'))\n ? {\n onAllReady() {\n pipeable!.pipe(reactAppPassthrough)\n },\n }\n : {\n onShellReady() {\n pipeable!.pipe(reactAppPassthrough)\n },\n }),\n onError: (error, info) => {\n console.error('Error in renderToPipeableStream:', error, info)\n abortPipeable(error, { defaultError: true })\n },\n })\n } catch (e) {\n console.error('Error in renderToPipeableStream:', e)\n router.serverSsr?.cleanup()\n throw e\n }\n\n const responseStream = transformPipeableStreamWithRouter(\n router,\n reactAppPassthrough,\n { onAbort: abortPipeable },\n )\n responseAttached = true\n\n if (endedBeforeAttach) {\n reactAppPassthrough.destroy(pendingDestroyError())\n }\n\n // React's onError may have fired synchronously inside\n // renderToPipeableStream before `pipeable` was assigned. If so,\n // abortPipeable ran without a pipeable handle; re-apply the abort now.\n if (aborted && pipeable) {\n try {\n pipeable.abort(toError(pendingAbortReason))\n } catch {\n // ignore — React may throw if already aborted/finished\n }\n }\n\n return createSsrStreamResponse(\n router,\n new Response(responseStream as any, {\n status: router.stores.statusCode.get(),\n headers: responseHeaders,\n }),\n )\n }\n\n throw new Error(\n 'No renderToReadableStream or renderToPipeableStream found in react-dom/server. Ensure you are using a version of react-dom that supports streaming.',\n )\n}\n"],"mappings":"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"} | ||
| {"version":3,"file":"renderRouterToStream.js","names":[],"sources":["../../../src/ssr/renderRouterToStream.tsx"],"sourcesContent":["import { PassThrough } from 'node:stream'\nimport ReactDOMServer from 'react-dom/server'\nimport { isbot } from 'isbot'\nimport {\n createSsrStreamResponse,\n transformPipeableStreamWithRouter,\n transformReadableStreamWithRouter,\n} from '@tanstack/router-core/ssr/server'\nimport type { AnyRouter } from '@tanstack/router-core'\nimport type { ReadableStream } from 'node:stream/web'\nimport type { ReactNode } from 'react'\n\nconst noop = () => {}\n\n// Bot responses wait for `allReady` so crawlers receive complete HTML.\n// If the request disconnects during that wait, React may not settle quickly;\n// unblock the wait so the response pipeline can abort and clean up.\nasync function waitForReadyOrAbort(\n ready: Promise<unknown>,\n signal: AbortSignal,\n) {\n let cleanup = noop\n try {\n await Promise.race([\n ready,\n new Promise<void>((resolve) => {\n const onAbort = () => resolve()\n cleanup = () => signal.removeEventListener('abort', onAbort)\n signal.addEventListener('abort', onAbort, { once: true })\n if (signal.aborted) resolve()\n }),\n ])\n } finally {\n cleanup()\n }\n}\n\n// A client disconnecting mid-stream is normal operation, not a render\n// failure; don't let React's onError log it as one.\nconst isAbortError = (request: Request, error: unknown) =>\n (request.signal.aborted && error === request.signal.reason) ||\n (error instanceof Error && error.name === 'AbortError')\n\nexport const renderRouterToStream = async ({\n request,\n router,\n responseHeaders,\n children,\n}: {\n request: Request\n router: AnyRouter\n responseHeaders: Headers\n children: ReactNode\n}) => {\n if (typeof ReactDOMServer.renderToReadableStream === 'function') {\n const stream = await ReactDOMServer.renderToReadableStream(children, {\n signal: request.signal,\n nonce: router.options.ssr?.nonce,\n progressiveChunkSize: Number.POSITIVE_INFINITY,\n onError: (error, info) => {\n if (!isAbortError(request, error)) {\n console.error('Error in renderToReadableStream:', error, info)\n }\n },\n })\n\n if (isbot(request.headers.get('User-Agent'))) {\n await waitForReadyOrAbort(stream.allReady, request.signal)\n }\n\n const responseStream = transformReadableStreamWithRouter(\n router,\n stream as unknown as ReadableStream,\n { onAbort: () => stream.cancel().catch(() => {}) },\n )\n return createSsrStreamResponse(\n router,\n new Response(responseStream as any, {\n status: router.stores.statusCode.get(),\n headers: responseHeaders,\n }),\n )\n }\n\n if (typeof ReactDOMServer.renderToPipeableStream === 'function') {\n const reactAppPassthrough = new PassThrough()\n\n let pipeable:\n | ReturnType<typeof ReactDOMServer.renderToPipeableStream>\n | undefined\n let responseAttached = false\n let aborted = false\n let endedBeforeAttach = false\n let pendingAbortReason: unknown\n const toError = (reason: unknown) =>\n reason instanceof Error\n ? reason\n : new Error(String(reason ?? 'SSR aborted'))\n const destroyError = (reason: unknown) =>\n reason === undefined ? undefined : toError(reason)\n const pendingDestroyError = () =>\n pendingAbortReason === undefined\n ? toError(pendingAbortReason)\n : destroyError(pendingAbortReason)\n const finishPassThrough = (\n reason: unknown,\n opts?: { defaultError?: boolean },\n ) => {\n if (reactAppPassthrough.destroyed) return\n if (responseAttached) {\n reactAppPassthrough.destroy(\n opts?.defaultError ? toError(reason) : destroyError(reason),\n )\n } else {\n endedBeforeAttach = true\n // onError can fire synchronously before React returns the pipeable\n // handle and before Readable.toWeb() is attached. Defer touching the\n // PassThrough until after the router transform can observe the error.\n }\n }\n const abortPipeable = (\n reason?: unknown,\n opts?: { defaultError?: boolean },\n ) => {\n if (aborted) return\n aborted = true\n pendingAbortReason = reason\n const err = toError(reason)\n try {\n pipeable?.abort(err)\n } catch {\n // ignore — React may throw if already aborted/finished\n }\n finishPassThrough(reason, opts)\n }\n\n // Register before attaching the router transform; the transform may\n // synchronously cleanup/error, and cleanup must still remove this listener.\n if (request.signal.aborted) {\n abortPipeable(request.signal.reason)\n } else {\n const onRequestAbort = () => abortPipeable(request.signal.reason)\n request.signal.addEventListener('abort', onRequestAbort, { once: true })\n router.serverSsr?.onCleanup(() => {\n request.signal.removeEventListener('abort', onRequestAbort)\n })\n }\n\n try {\n pipeable = ReactDOMServer.renderToPipeableStream(children, {\n nonce: router.options.ssr?.nonce,\n progressiveChunkSize: Number.POSITIVE_INFINITY,\n ...(isbot(request.headers.get('User-Agent'))\n ? {\n onAllReady() {\n pipeable!.pipe(reactAppPassthrough)\n },\n }\n : {\n onShellReady() {\n pipeable!.pipe(reactAppPassthrough)\n },\n }),\n onError: (error, info) => {\n if (!isAbortError(request, error)) {\n console.error('Error in renderToPipeableStream:', error, info)\n }\n abortPipeable(error, { defaultError: true })\n },\n })\n } catch (e) {\n console.error('Error in renderToPipeableStream:', e)\n router.serverSsr?.cleanup()\n throw e\n }\n\n const responseStream = transformPipeableStreamWithRouter(\n router,\n reactAppPassthrough,\n { onAbort: abortPipeable },\n )\n responseAttached = true\n\n if (endedBeforeAttach) {\n reactAppPassthrough.destroy(pendingDestroyError())\n }\n\n // React's onError may have fired synchronously inside\n // renderToPipeableStream before `pipeable` was assigned. If so,\n // abortPipeable ran without a pipeable handle; re-apply the abort now.\n if (aborted && pipeable) {\n try {\n pipeable.abort(toError(pendingAbortReason))\n } catch {\n // ignore — React may throw if already aborted/finished\n }\n }\n\n return createSsrStreamResponse(\n router,\n new Response(responseStream as any, {\n status: router.stores.statusCode.get(),\n headers: responseHeaders,\n }),\n )\n }\n\n throw new Error(\n 'No renderToReadableStream or renderToPipeableStream found in react-dom/server. Ensure you are using a version of react-dom that supports streaming.',\n )\n}\n"],"mappings":"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"} |
| "use client"; | ||
| import { useRouter } from "./useRouter.js"; | ||
| import { replaceEqualDeep } from "@tanstack/router-core"; | ||
| import { useRef } from "react"; | ||
| import { useStructuralSharing } from "./useMatch.js"; | ||
| import { useStore } from "@tanstack/react-store"; | ||
@@ -25,12 +24,3 @@ import { isServer } from "@tanstack/router-core/isServer"; | ||
| } | ||
| const previousResult = useRef(void 0); | ||
| return useStore(router.stores.location, (location) => { | ||
| const selected = opts?.select ? opts.select(location) : location; | ||
| if (opts?.structuralSharing ?? router.options.defaultStructuralSharing) { | ||
| const shared = replaceEqualDeep(previousResult.current, selected); | ||
| previousResult.current = shared; | ||
| return shared; | ||
| } | ||
| return selected; | ||
| }); | ||
| return useStore(router.stores.location, useStructuralSharing(opts, router)); | ||
| } | ||
@@ -37,0 +27,0 @@ //#endregion |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"useLocation.js","names":[],"sources":["../../src/useLocation.tsx"],"sourcesContent":["'use client'\n\nimport { useStore } from '@tanstack/react-store'\nimport { useRef } from 'react'\nimport { replaceEqualDeep } from '@tanstack/router-core'\nimport { isServer } from '@tanstack/router-core/isServer'\nimport { useRouter } from './useRouter'\nimport type {\n StructuralSharingOption,\n ValidateSelected,\n} from './structuralSharing'\nimport type {\n AnyRouter,\n RegisteredRouter,\n RouterState,\n} from '@tanstack/router-core'\n\nexport interface UseLocationBaseOptions<\n TRouter extends AnyRouter,\n TSelected,\n TStructuralSharing extends boolean = boolean,\n> {\n select?: (\n state: RouterState<TRouter['routeTree']>['location'],\n ) => ValidateSelected<TRouter, TSelected, TStructuralSharing>\n}\n\nexport type UseLocationResult<\n TRouter extends AnyRouter,\n TSelected,\n> = unknown extends TSelected\n ? RouterState<TRouter['routeTree']>['location']\n : TSelected\n\n/**\n * Read the current location from the router state with optional selection.\n * Useful for subscribing to just the pieces of location you care about.\n *\n * Options:\n * - `select`: Project the `location` object to a derived value\n * - `structuralSharing`: Enable structural sharing for stable references\n *\n * @returns The current location (or selected value).\n * @link https://tanstack.com/router/latest/docs/framework/react/api/router/useLocationHook\n */\nexport function useLocation<\n TRouter extends AnyRouter = RegisteredRouter,\n TSelected = unknown,\n TStructuralSharing extends boolean = boolean,\n>(\n opts?: UseLocationBaseOptions<TRouter, TSelected, TStructuralSharing> &\n StructuralSharingOption<TRouter, TSelected, TStructuralSharing>,\n): UseLocationResult<TRouter, TSelected> {\n const router = useRouter<TRouter>()\n\n if (isServer ?? router.isServer) {\n const location = router.stores.location.get()\n return (\n opts?.select ? opts.select(location as any) : location\n ) as UseLocationResult<TRouter, TSelected>\n }\n\n const previousResult =\n // eslint-disable-next-line react-hooks/rules-of-hooks -- condition is static\n useRef<ValidateSelected<TRouter, TSelected, TStructuralSharing>>(undefined)\n\n // eslint-disable-next-line react-hooks/rules-of-hooks -- condition is static\n return useStore(router.stores.location, (location) => {\n const selected = (\n opts?.select ? opts.select(location as any) : location\n ) as ValidateSelected<TRouter, TSelected, TStructuralSharing>\n\n if (opts?.structuralSharing ?? router.options.defaultStructuralSharing) {\n const shared = replaceEqualDeep(previousResult.current, selected)\n previousResult.current = shared\n return shared\n }\n\n return selected\n }) as UseLocationResult<TRouter, TSelected>\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AA6CA,SAAgB,YAKd,MAEuC;CACvC,MAAM,SAAS,UAAmB;CAElC,IAAI,YAAY,OAAO,UAAU;EAC/B,MAAM,WAAW,OAAO,OAAO,SAAS,IAAI;EAC5C,OACE,MAAM,SAAS,KAAK,OAAO,QAAe,IAAI;CAElD;CAEA,MAAM,iBAEJ,OAAiE,KAAA,CAAS;CAG5E,OAAO,SAAS,OAAO,OAAO,WAAW,aAAa;EACpD,MAAM,WACJ,MAAM,SAAS,KAAK,OAAO,QAAe,IAAI;EAGhD,IAAI,MAAM,qBAAqB,OAAO,QAAQ,0BAA0B;GACtE,MAAM,SAAS,iBAAiB,eAAe,SAAS,QAAQ;GAChE,eAAe,UAAU;GACzB,OAAO;EACT;EAEA,OAAO;CACT,CAAC;AACH"} | ||
| {"version":3,"file":"useLocation.js","names":[],"sources":["../../src/useLocation.tsx"],"sourcesContent":["'use client'\n\nimport { useStore } from '@tanstack/react-store'\nimport { isServer } from '@tanstack/router-core/isServer'\nimport { useRouter } from './useRouter'\nimport { useStructuralSharing } from './useMatch'\nimport type {\n StructuralSharingOption,\n ValidateSelected,\n} from './structuralSharing'\nimport type {\n AnyRouter,\n RegisteredRouter,\n RouterState,\n} from '@tanstack/router-core'\n\nexport interface UseLocationBaseOptions<\n TRouter extends AnyRouter,\n TSelected,\n TStructuralSharing extends boolean = boolean,\n> {\n select?: (\n state: RouterState<TRouter['routeTree']>['location'],\n ) => ValidateSelected<TRouter, TSelected, TStructuralSharing>\n}\n\nexport type UseLocationResult<\n TRouter extends AnyRouter,\n TSelected,\n> = unknown extends TSelected\n ? RouterState<TRouter['routeTree']>['location']\n : TSelected\n\n/**\n * Read the current location from the router state with optional selection.\n * Useful for subscribing to just the pieces of location you care about.\n *\n * Options:\n * - `select`: Project the `location` object to a derived value\n * - `structuralSharing`: Enable structural sharing for stable references\n *\n * @returns The current location (or selected value).\n * @link https://tanstack.com/router/latest/docs/framework/react/api/router/useLocationHook\n */\nexport function useLocation<\n TRouter extends AnyRouter = RegisteredRouter,\n TSelected = unknown,\n TStructuralSharing extends boolean = boolean,\n>(\n opts?: UseLocationBaseOptions<TRouter, TSelected, TStructuralSharing> &\n StructuralSharingOption<TRouter, TSelected, TStructuralSharing>,\n): UseLocationResult<TRouter, TSelected> {\n const router = useRouter<TRouter>()\n\n if (isServer ?? router.isServer) {\n const location = router.stores.location.get()\n return (\n opts?.select ? opts.select(location as any) : location\n ) as UseLocationResult<TRouter, TSelected>\n }\n\n // eslint-disable-next-line react-hooks/rules-of-hooks -- condition is static\n return useStore(\n router.stores.location,\n // eslint-disable-next-line react-hooks/rules-of-hooks -- condition is static\n useStructuralSharing(opts, router),\n ) as UseLocationResult<TRouter, TSelected>\n}\n"],"mappings":";;;;;;;;;;;;;;;;;AA4CA,SAAgB,YAKd,MAEuC;CACvC,MAAM,SAAS,UAAmB;CAElC,IAAI,YAAY,OAAO,UAAU;EAC/B,MAAM,WAAW,OAAO,OAAO,SAAS,IAAI;EAC5C,OACE,MAAM,SAAS,KAAK,OAAO,QAAe,IAAI;CAElD;CAGA,OAAO,SACL,OAAO,OAAO,UAEd,qBAAqB,MAAM,MAAM,CACnC;AACF"} |
| import { StructuralSharingOption, ValidateSelected } from './structuralSharing.js'; | ||
| import { AnyRouter, MakeRouteMatch, MakeRouteMatchUnion, RegisteredRouter, StrictOrFrom, ThrowConstraint, ThrowOrOptional } from '@tanstack/router-core'; | ||
| export declare function useStructuralSharing<TRouter extends AnyRouter, TSelected, TStructuralSharing extends boolean, TStoreSlice, TSelectSlice = TStoreSlice>(opts: { | ||
| select?: (slice: TSelectSlice) => ValidateSelected<TRouter, TSelected, TStructuralSharing>; | ||
| structuralSharing?: boolean; | ||
| } | undefined, router: TRouter): (slice: TStoreSlice) => ValidateSelected<TRouter, TSelected, TStructuralSharing>; | ||
| export interface UseMatchBaseOptions<TRouter extends AnyRouter, TFrom, TStrict extends boolean, TThrow extends boolean, TSelected, TStructuralSharing extends boolean> { | ||
@@ -4,0 +8,0 @@ select?: (match: MakeRouteMatch<TRouter['routeTree'], TFrom, TStrict>) => ValidateSelected<TRouter, TSelected, TStructuralSharing>; |
+27
-24
@@ -10,5 +10,15 @@ "use client"; | ||
| var dummyStore = { | ||
| get: () => void 0, | ||
| subscribe: () => ({ unsubscribe: () => {} }) | ||
| get() {}, | ||
| subscribe() { | ||
| return { unsubscribe() {} }; | ||
| } | ||
| }; | ||
| function useStructuralSharing(opts, router) { | ||
| const previousResult = React$1.useRef(); | ||
| return (slice) => { | ||
| const selected = opts?.select ? opts.select(slice) : slice; | ||
| if (opts?.structuralSharing ?? router.options.defaultStructuralSharing) return previousResult.current = replaceEqualDeep(previousResult.current, selected); | ||
| return selected; | ||
| }; | ||
| } | ||
| /** | ||
@@ -21,32 +31,25 @@ * Read and select the nearest or targeted route match. | ||
| const nearestMatchId = React$1.useContext(opts.from ? dummyMatchContext : matchContext); | ||
| const key = opts.from ?? nearestMatchId; | ||
| const matchStore = key ? opts.from ? router.stores.getRouteMatchStore(key) : router.stores.matchStores.get(key) : void 0; | ||
| const matchStore = opts.from ? router.stores.getRouteMatchStore(opts.from) : router.stores.matchStores.get(nearestMatchId); | ||
| if (isServer ?? router.isServer) { | ||
| const match = matchStore?.get(); | ||
| if ((opts.shouldThrow ?? true) && !match) { | ||
| if (process.env.NODE_ENV !== "production") throw new Error(`Invariant failed: Could not find ${opts.from ? `an active match from "${opts.from}"` : "a nearest match!"}`); | ||
| invariant(); | ||
| if (!match) { | ||
| if (opts.shouldThrow ?? true) { | ||
| if (process.env.NODE_ENV !== "production") throw new Error(`Invariant failed: Could not find ${opts.from ? `an active match from "${opts.from}"` : "a nearest match!"}`); | ||
| invariant(); | ||
| } | ||
| return; | ||
| } | ||
| if (match === void 0) return; | ||
| return opts.select ? opts.select(match) : match; | ||
| } | ||
| const previousResult = React$1.useRef(void 0); | ||
| return useStore(matchStore ?? dummyStore, (match) => { | ||
| if ((opts.shouldThrow ?? true) && !match) { | ||
| if (process.env.NODE_ENV !== "production") throw new Error(`Invariant failed: Could not find ${opts.from ? `an active match from "${opts.from}"` : "a nearest match!"}`); | ||
| invariant(); | ||
| } | ||
| if (match === void 0) return; | ||
| const selected = opts.select ? opts.select(match) : match; | ||
| if (opts.structuralSharing ?? router.options.defaultStructuralSharing) { | ||
| const shared = replaceEqualDeep(previousResult.current, selected); | ||
| previousResult.current = shared; | ||
| return shared; | ||
| } | ||
| return selected; | ||
| }); | ||
| const selector = useStructuralSharing(opts, router); | ||
| const matchSelection = useStore(matchStore ?? dummyStore, (match) => match ? selector(match) : dummyStore); | ||
| if (matchSelection !== dummyStore) return matchSelection; | ||
| if (opts.shouldThrow ?? true) { | ||
| if (process.env.NODE_ENV !== "production") throw new Error(`Invariant failed: Could not find ${opts.from ? `an active match from "${opts.from}"` : "a nearest match!"}`); | ||
| invariant(); | ||
| } | ||
| } | ||
| //#endregion | ||
| export { useMatch }; | ||
| export { useMatch, useStructuralSharing }; | ||
| //# sourceMappingURL=useMatch.js.map |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"useMatch.js","names":[],"sources":["../../src/useMatch.tsx"],"sourcesContent":["'use client'\n\nimport * as React from 'react'\nimport { useStore } from '@tanstack/react-store'\nimport { invariant, replaceEqualDeep } from '@tanstack/router-core'\nimport { isServer } from '@tanstack/router-core/isServer'\nimport { dummyMatchContext, matchContext } from './matchContext'\nimport { useRouter } from './useRouter'\nimport type {\n StructuralSharingOption,\n ValidateSelected,\n} from './structuralSharing'\nimport type {\n AnyRouter,\n MakeRouteMatch,\n MakeRouteMatchUnion,\n RegisteredRouter,\n StrictOrFrom,\n ThrowConstraint,\n ThrowOrOptional,\n} from '@tanstack/router-core'\n\nconst dummyStore = {\n get: () => undefined,\n subscribe: () => ({ unsubscribe: () => {} }),\n} as any\n\nexport interface UseMatchBaseOptions<\n TRouter extends AnyRouter,\n TFrom,\n TStrict extends boolean,\n TThrow extends boolean,\n TSelected,\n TStructuralSharing extends boolean,\n> {\n select?: (\n match: MakeRouteMatch<TRouter['routeTree'], TFrom, TStrict>,\n ) => ValidateSelected<TRouter, TSelected, TStructuralSharing>\n shouldThrow?: TThrow\n}\n\nexport type UseMatchRoute<out TFrom> = <\n TRouter extends AnyRouter = RegisteredRouter,\n TSelected = unknown,\n TStructuralSharing extends boolean = boolean,\n>(\n opts?: UseMatchBaseOptions<\n TRouter,\n TFrom,\n true,\n true,\n TSelected,\n TStructuralSharing\n > &\n StructuralSharingOption<TRouter, TSelected, TStructuralSharing>,\n) => UseMatchResult<TRouter, TFrom, true, TSelected>\n\nexport type UseMatchOptions<\n TRouter extends AnyRouter,\n TFrom extends string | undefined,\n TStrict extends boolean,\n TThrow extends boolean,\n TSelected,\n TStructuralSharing extends boolean,\n> = StrictOrFrom<TRouter, TFrom, TStrict> &\n UseMatchBaseOptions<\n TRouter,\n TFrom,\n TStrict,\n TThrow,\n TSelected,\n TStructuralSharing\n > &\n StructuralSharingOption<TRouter, TSelected, TStructuralSharing>\n\nexport type UseMatchResult<\n TRouter extends AnyRouter,\n TFrom,\n TStrict extends boolean,\n TSelected,\n> = unknown extends TSelected\n ? TStrict extends true\n ? MakeRouteMatch<TRouter['routeTree'], TFrom, TStrict>\n : MakeRouteMatchUnion<TRouter>\n : TSelected\n\n/**\n * Read and select the nearest or targeted route match.\n * @link https://tanstack.com/router/latest/docs/framework/react/api/router/useMatchHook\n */\nexport function useMatch<\n TRouter extends AnyRouter = RegisteredRouter,\n const TFrom extends string | undefined = undefined,\n TStrict extends boolean = true,\n TThrow extends boolean = true,\n TSelected = unknown,\n TStructuralSharing extends boolean = boolean,\n>(\n opts: UseMatchOptions<\n TRouter,\n TFrom,\n TStrict,\n ThrowConstraint<TStrict, TThrow>,\n TSelected,\n TStructuralSharing\n >,\n): ThrowOrOptional<UseMatchResult<TRouter, TFrom, TStrict, TSelected>, TThrow> {\n const router = useRouter<TRouter>()\n const nearestMatchId = React.useContext(\n opts.from ? dummyMatchContext : matchContext,\n )\n\n const key = opts.from ?? nearestMatchId\n const matchStore = key\n ? opts.from\n ? router.stores.getRouteMatchStore(key)\n : router.stores.matchStores.get(key)\n : undefined\n\n if (isServer ?? router.isServer) {\n const match = matchStore?.get()\n if ((opts.shouldThrow ?? true) && !match) {\n if (process.env.NODE_ENV !== 'production') {\n throw new Error(\n `Invariant failed: Could not find ${opts.from ? `an active match from \"${opts.from}\"` : 'a nearest match!'}`,\n )\n }\n\n invariant()\n }\n\n if (match === undefined) {\n return undefined as any\n }\n\n return (opts.select ? opts.select(match as any) : match) as any\n }\n\n const previousResult =\n // eslint-disable-next-line react-hooks/rules-of-hooks -- condition is static\n React.useRef<ValidateSelected<TRouter, TSelected, TStructuralSharing>>(\n undefined,\n )\n\n // eslint-disable-next-line react-hooks/rules-of-hooks -- condition is static\n return useStore(matchStore ?? dummyStore, (match) => {\n if ((opts.shouldThrow ?? true) && !match) {\n if (process.env.NODE_ENV !== 'production') {\n throw new Error(\n `Invariant failed: Could not find ${opts.from ? `an active match from \"${opts.from}\"` : 'a nearest match!'}`,\n )\n }\n\n invariant()\n }\n\n if (match === undefined) {\n return undefined\n }\n\n const selected = (\n opts.select ? opts.select(match as any) : match\n ) as ValidateSelected<TRouter, TSelected, TStructuralSharing>\n\n if (opts.structuralSharing ?? router.options.defaultStructuralSharing) {\n const shared = replaceEqualDeep(previousResult.current, selected)\n previousResult.current = shared\n return shared\n }\n\n return selected\n }) as any\n}\n"],"mappings":";;;;;;;;AAsBA,IAAM,aAAa;CACjB,WAAW,KAAA;CACX,kBAAkB,EAAE,mBAAmB,CAAC,EAAE;AAC5C;;;;;AAiEA,SAAgB,SAQd,MAQ6E;CAC7E,MAAM,SAAS,UAAmB;CAClC,MAAM,iBAAiB,QAAM,WAC3B,KAAK,OAAO,oBAAoB,YAClC;CAEA,MAAM,MAAM,KAAK,QAAQ;CACzB,MAAM,aAAa,MACf,KAAK,OACH,OAAO,OAAO,mBAAmB,GAAG,IACpC,OAAO,OAAO,YAAY,IAAI,GAAG,IACnC,KAAA;CAEJ,IAAI,YAAY,OAAO,UAAU;EAC/B,MAAM,QAAQ,YAAY,IAAI;EAC9B,KAAK,KAAK,eAAe,SAAS,CAAC,OAAO;GACxC,IAAA,QAAA,IAAA,aAA6B,cAC3B,MAAM,IAAI,MACR,oCAAoC,KAAK,OAAO,yBAAyB,KAAK,KAAK,KAAK,oBAC1F;GAGF,UAAU;EACZ;EAEA,IAAI,UAAU,KAAA,GACZ;EAGF,OAAQ,KAAK,SAAS,KAAK,OAAO,KAAY,IAAI;CACpD;CAEA,MAAM,iBAEJ,QAAM,OACJ,KAAA,CACF;CAGF,OAAO,SAAS,cAAc,aAAa,UAAU;EACnD,KAAK,KAAK,eAAe,SAAS,CAAC,OAAO;GACxC,IAAA,QAAA,IAAA,aAA6B,cAC3B,MAAM,IAAI,MACR,oCAAoC,KAAK,OAAO,yBAAyB,KAAK,KAAK,KAAK,oBAC1F;GAGF,UAAU;EACZ;EAEA,IAAI,UAAU,KAAA,GACZ;EAGF,MAAM,WACJ,KAAK,SAAS,KAAK,OAAO,KAAY,IAAI;EAG5C,IAAI,KAAK,qBAAqB,OAAO,QAAQ,0BAA0B;GACrE,MAAM,SAAS,iBAAiB,eAAe,SAAS,QAAQ;GAChE,eAAe,UAAU;GACzB,OAAO;EACT;EAEA,OAAO;CACT,CAAC;AACH"} | ||
| {"version":3,"file":"useMatch.js","names":[],"sources":["../../src/useMatch.tsx"],"sourcesContent":["'use client'\n\nimport * as React from 'react'\nimport { useStore } from '@tanstack/react-store'\nimport { invariant, replaceEqualDeep } from '@tanstack/router-core'\nimport { isServer } from '@tanstack/router-core/isServer'\nimport { dummyMatchContext, matchContext } from './matchContext'\nimport { useRouter } from './useRouter'\nimport type {\n StructuralSharingOption,\n ValidateSelected,\n} from './structuralSharing'\nimport type {\n AnyRouter,\n MakeRouteMatch,\n MakeRouteMatchUnion,\n RegisteredRouter,\n StrictOrFrom,\n ThrowConstraint,\n ThrowOrOptional,\n} from '@tanstack/router-core'\n\nconst dummyStore = {\n get() {},\n subscribe() {\n return { unsubscribe() {} }\n },\n} as any\n\nexport function useStructuralSharing<\n TRouter extends AnyRouter,\n TSelected,\n TStructuralSharing extends boolean,\n TStoreSlice,\n TSelectSlice = TStoreSlice,\n>(\n opts:\n | {\n select?: (\n slice: TSelectSlice,\n ) => ValidateSelected<TRouter, TSelected, TStructuralSharing>\n structuralSharing?: boolean\n }\n | undefined,\n router: TRouter,\n): (\n slice: TStoreSlice,\n) => ValidateSelected<TRouter, TSelected, TStructuralSharing> {\n const previousResult =\n // @ts-expect-error -- init to undefined, but without writing `undefined` to shave bytes\n React.useRef<ValidateSelected<TRouter, TSelected, TStructuralSharing>>()\n\n return (slice) => {\n const selected = opts?.select\n ? opts.select(slice as unknown as TSelectSlice)\n : (slice as ValidateSelected<TRouter, TSelected, TStructuralSharing>)\n\n if (opts?.structuralSharing ?? router.options.defaultStructuralSharing) {\n return (previousResult.current = replaceEqualDeep(\n previousResult.current,\n selected,\n ))\n }\n\n return selected\n }\n}\n\nexport interface UseMatchBaseOptions<\n TRouter extends AnyRouter,\n TFrom,\n TStrict extends boolean,\n TThrow extends boolean,\n TSelected,\n TStructuralSharing extends boolean,\n> {\n select?: (\n match: MakeRouteMatch<TRouter['routeTree'], TFrom, TStrict>,\n ) => ValidateSelected<TRouter, TSelected, TStructuralSharing>\n shouldThrow?: TThrow\n}\n\nexport type UseMatchRoute<out TFrom> = <\n TRouter extends AnyRouter = RegisteredRouter,\n TSelected = unknown,\n TStructuralSharing extends boolean = boolean,\n>(\n opts?: UseMatchBaseOptions<\n TRouter,\n TFrom,\n true,\n true,\n TSelected,\n TStructuralSharing\n > &\n StructuralSharingOption<TRouter, TSelected, TStructuralSharing>,\n) => UseMatchResult<TRouter, TFrom, true, TSelected>\n\nexport type UseMatchOptions<\n TRouter extends AnyRouter,\n TFrom extends string | undefined,\n TStrict extends boolean,\n TThrow extends boolean,\n TSelected,\n TStructuralSharing extends boolean,\n> = StrictOrFrom<TRouter, TFrom, TStrict> &\n UseMatchBaseOptions<\n TRouter,\n TFrom,\n TStrict,\n TThrow,\n TSelected,\n TStructuralSharing\n > &\n StructuralSharingOption<TRouter, TSelected, TStructuralSharing>\n\nexport type UseMatchResult<\n TRouter extends AnyRouter,\n TFrom,\n TStrict extends boolean,\n TSelected,\n> = unknown extends TSelected\n ? TStrict extends true\n ? MakeRouteMatch<TRouter['routeTree'], TFrom, TStrict>\n : MakeRouteMatchUnion<TRouter>\n : TSelected\n\n/**\n * Read and select the nearest or targeted route match.\n * @link https://tanstack.com/router/latest/docs/framework/react/api/router/useMatchHook\n */\nexport function useMatch<\n TRouter extends AnyRouter = RegisteredRouter,\n const TFrom extends string | undefined = undefined,\n TStrict extends boolean = true,\n TThrow extends boolean = true,\n TSelected = unknown,\n TStructuralSharing extends boolean = boolean,\n>(\n opts: UseMatchOptions<\n TRouter,\n TFrom,\n TStrict,\n ThrowConstraint<TStrict, TThrow>,\n TSelected,\n TStructuralSharing\n >,\n): ThrowOrOptional<UseMatchResult<TRouter, TFrom, TStrict, TSelected>, TThrow> {\n const router = useRouter<TRouter>()\n const nearestMatchId = React.useContext(\n opts.from ? dummyMatchContext : matchContext,\n )\n\n const matchStore = opts.from\n ? router.stores.getRouteMatchStore(opts.from)\n : router.stores.matchStores.get(nearestMatchId!)\n\n if (isServer ?? router.isServer) {\n const match = matchStore?.get()\n if (!match) {\n if (opts.shouldThrow ?? true) {\n if (process.env.NODE_ENV !== 'production') {\n throw new Error(\n `Invariant failed: Could not find ${opts.from ? `an active match from \"${opts.from}\"` : 'a nearest match!'}`,\n )\n }\n\n invariant()\n }\n\n return undefined as any\n }\n\n return (opts.select ? opts.select(match as any) : match) as any\n }\n\n const selector =\n // eslint-disable-next-line react-hooks/rules-of-hooks -- condition is static\n useStructuralSharing(opts, router)\n\n // eslint-disable-next-line react-hooks/rules-of-hooks -- condition is static\n const matchSelection = useStore(matchStore ?? dummyStore, (match) =>\n match ? selector(match as any) : dummyStore,\n )\n\n if (matchSelection !== dummyStore) {\n return matchSelection\n }\n\n if (opts.shouldThrow ?? true) {\n if (process.env.NODE_ENV !== 'production') {\n throw new Error(\n `Invariant failed: Could not find ${opts.from ? `an active match from \"${opts.from}\"` : 'a nearest match!'}`,\n )\n }\n\n invariant()\n }\n\n return undefined as any\n}\n"],"mappings":";;;;;;;;AAsBA,IAAM,aAAa;CACjB,MAAM,CAAC;CACP,YAAY;EACV,OAAO,EAAE,cAAc,CAAC,EAAE;CAC5B;AACF;AAEA,SAAgB,qBAOd,MAQA,QAG4D;CAC5D,MAAM,iBAEJ,QAAM,OAAiE;CAEzE,QAAQ,UAAU;EAChB,MAAM,WAAW,MAAM,SACnB,KAAK,OAAO,KAAgC,IAC3C;EAEL,IAAI,MAAM,qBAAqB,OAAO,QAAQ,0BAC5C,OAAQ,eAAe,UAAU,iBAC/B,eAAe,SACf,QACF;EAGF,OAAO;CACT;AACF;;;;;AAiEA,SAAgB,SAQd,MAQ6E;CAC7E,MAAM,SAAS,UAAmB;CAClC,MAAM,iBAAiB,QAAM,WAC3B,KAAK,OAAO,oBAAoB,YAClC;CAEA,MAAM,aAAa,KAAK,OACpB,OAAO,OAAO,mBAAmB,KAAK,IAAI,IAC1C,OAAO,OAAO,YAAY,IAAI,cAAe;CAEjD,IAAI,YAAY,OAAO,UAAU;EAC/B,MAAM,QAAQ,YAAY,IAAI;EAC9B,IAAI,CAAC,OAAO;GACV,IAAI,KAAK,eAAe,MAAM;IAC5B,IAAA,QAAA,IAAA,aAA6B,cAC3B,MAAM,IAAI,MACR,oCAAoC,KAAK,OAAO,yBAAyB,KAAK,KAAK,KAAK,oBAC1F;IAGF,UAAU;GACZ;GAEA;EACF;EAEA,OAAQ,KAAK,SAAS,KAAK,OAAO,KAAY,IAAI;CACpD;CAEA,MAAM,WAEJ,qBAAqB,MAAM,MAAM;CAGnC,MAAM,iBAAiB,SAAS,cAAc,aAAa,UACzD,QAAQ,SAAS,KAAY,IAAI,UACnC;CAEA,IAAI,mBAAmB,YACrB,OAAO;CAGT,IAAI,KAAK,eAAe,MAAM;EAC5B,IAAA,QAAA,IAAA,aAA6B,cAC3B,MAAM,IAAI,MACR,oCAAoC,KAAK,OAAO,yBAAyB,KAAK,KAAK,KAAK,oBAC1F;EAGF,UAAU;CACZ;AAGF"} |
| "use client"; | ||
| import { useRouter } from "./useRouter.js"; | ||
| import { replaceEqualDeep } from "@tanstack/router-core"; | ||
| import { useRef } from "react"; | ||
| import { useStructuralSharing } from "./useMatch.js"; | ||
| import { useStore } from "@tanstack/react-store"; | ||
@@ -27,14 +26,3 @@ import { isServer } from "@tanstack/router-core/isServer"; | ||
| } | ||
| const previousResult = useRef(void 0); | ||
| return useStore(router.stores.__store, (state) => { | ||
| if (opts?.select) { | ||
| if (opts.structuralSharing ?? router.options.defaultStructuralSharing) { | ||
| const newSlice = replaceEqualDeep(previousResult.current, opts.select(state)); | ||
| previousResult.current = newSlice; | ||
| return newSlice; | ||
| } | ||
| return opts.select(state); | ||
| } | ||
| return state; | ||
| }); | ||
| return useStore(router.stores.__store, useStructuralSharing(opts, router)); | ||
| } | ||
@@ -41,0 +29,0 @@ //#endregion |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"useRouterState.js","names":[],"sources":["../../src/useRouterState.tsx"],"sourcesContent":["'use client'\n\nimport { useStore } from '@tanstack/react-store'\nimport { useRef } from 'react'\nimport { replaceEqualDeep } from '@tanstack/router-core'\nimport { isServer } from '@tanstack/router-core/isServer'\nimport { useRouter } from './useRouter'\nimport type {\n AnyRouter,\n RegisteredRouter,\n RouterState,\n} from '@tanstack/router-core'\nimport type {\n StructuralSharingOption,\n ValidateSelected,\n} from './structuralSharing'\n\nexport type UseRouterStateOptions<\n TRouter extends AnyRouter,\n TSelected,\n TStructuralSharing,\n> = {\n router?: TRouter\n select?: (\n state: RouterState<TRouter['routeTree']>,\n ) => ValidateSelected<TRouter, TSelected, TStructuralSharing>\n} & StructuralSharingOption<TRouter, TSelected, TStructuralSharing>\n\nexport type UseRouterStateResult<\n TRouter extends AnyRouter,\n TSelected,\n> = unknown extends TSelected ? RouterState<TRouter['routeTree']> : TSelected\n\n/**\n * Subscribe to the router's state store with optional selection and\n * structural sharing for render optimization.\n *\n * Options:\n * - `select`: Project the full router state to a derived slice\n * - `structuralSharing`: Replace-equal semantics for stable references\n * - `router`: Read state from a specific router instance instead of context\n *\n * @returns The selected router state (or the full state by default).\n * @link https://tanstack.com/router/latest/docs/framework/react/api/router/useRouterStateHook\n */\nexport function useRouterState<\n TRouter extends AnyRouter = RegisteredRouter,\n TSelected = unknown,\n TStructuralSharing extends boolean = boolean,\n>(\n opts?: UseRouterStateOptions<TRouter, TSelected, TStructuralSharing>,\n): UseRouterStateResult<TRouter, TSelected> {\n const contextRouter = useRouter<TRouter>({\n warn: opts?.router === undefined,\n })\n const router = opts?.router || contextRouter\n\n // During SSR we render exactly once and do not need reactivity.\n // Avoid subscribing to the store (and any structural sharing work) on the server.\n const _isServer = isServer ?? router.isServer\n if (_isServer) {\n const state = router.stores.__store.get() as RouterState<\n TRouter['routeTree']\n >\n return (opts?.select ? opts.select(state) : state) as UseRouterStateResult<\n TRouter,\n TSelected\n >\n }\n\n const previousResult =\n // eslint-disable-next-line react-hooks/rules-of-hooks\n useRef<ValidateSelected<TRouter, TSelected, TStructuralSharing>>(undefined)\n\n // eslint-disable-next-line react-hooks/rules-of-hooks\n return useStore(router.stores.__store, (state) => {\n if (opts?.select) {\n if (opts.structuralSharing ?? router.options.defaultStructuralSharing) {\n const newSlice = replaceEqualDeep(\n previousResult.current,\n opts.select(state),\n )\n previousResult.current = newSlice\n return newSlice\n }\n return opts.select(state)\n }\n return state\n }) as UseRouterStateResult<TRouter, TSelected>\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;AA6CA,SAAgB,eAKd,MAC0C;CAC1C,MAAM,gBAAgB,UAAmB,EACvC,MAAM,MAAM,WAAW,KAAA,EACzB,CAAC;CACD,MAAM,SAAS,MAAM,UAAU;CAK/B,IADkB,YAAY,OAAO,UACtB;EACb,MAAM,QAAQ,OAAO,OAAO,QAAQ,IAAI;EAGxC,OAAQ,MAAM,SAAS,KAAK,OAAO,KAAK,IAAI;CAI9C;CAEA,MAAM,iBAEJ,OAAiE,KAAA,CAAS;CAG5E,OAAO,SAAS,OAAO,OAAO,UAAU,UAAU;EAChD,IAAI,MAAM,QAAQ;GAChB,IAAI,KAAK,qBAAqB,OAAO,QAAQ,0BAA0B;IACrE,MAAM,WAAW,iBACf,eAAe,SACf,KAAK,OAAO,KAAK,CACnB;IACA,eAAe,UAAU;IACzB,OAAO;GACT;GACA,OAAO,KAAK,OAAO,KAAK;EAC1B;EACA,OAAO;CACT,CAAC;AACH"} | ||
| {"version":3,"file":"useRouterState.js","names":[],"sources":["../../src/useRouterState.tsx"],"sourcesContent":["'use client'\n\nimport { useStore } from '@tanstack/react-store'\nimport { isServer } from '@tanstack/router-core/isServer'\nimport { useRouter } from './useRouter'\nimport { useStructuralSharing } from './useMatch'\nimport type {\n AnyRouter,\n RegisteredRouter,\n RouterState,\n} from '@tanstack/router-core'\nimport type {\n StructuralSharingOption,\n ValidateSelected,\n} from './structuralSharing'\n\nexport type UseRouterStateOptions<\n TRouter extends AnyRouter,\n TSelected,\n TStructuralSharing,\n> = {\n router?: TRouter\n select?: (\n state: RouterState<TRouter['routeTree']>,\n ) => ValidateSelected<TRouter, TSelected, TStructuralSharing>\n} & StructuralSharingOption<TRouter, TSelected, TStructuralSharing>\n\nexport type UseRouterStateResult<\n TRouter extends AnyRouter,\n TSelected,\n> = unknown extends TSelected ? RouterState<TRouter['routeTree']> : TSelected\n\n/**\n * Subscribe to the router's state store with optional selection and\n * structural sharing for render optimization.\n *\n * Options:\n * - `select`: Project the full router state to a derived slice\n * - `structuralSharing`: Replace-equal semantics for stable references\n * - `router`: Read state from a specific router instance instead of context\n *\n * @returns The selected router state (or the full state by default).\n * @link https://tanstack.com/router/latest/docs/framework/react/api/router/useRouterStateHook\n */\nexport function useRouterState<\n TRouter extends AnyRouter = RegisteredRouter,\n TSelected = unknown,\n TStructuralSharing extends boolean = boolean,\n>(\n opts?: UseRouterStateOptions<TRouter, TSelected, TStructuralSharing>,\n): UseRouterStateResult<TRouter, TSelected> {\n const contextRouter = useRouter<TRouter>({\n warn: opts?.router === undefined,\n })\n const router = opts?.router || contextRouter\n\n // During SSR we render exactly once and do not need reactivity.\n // Avoid subscribing to the store (and any structural sharing work) on the server.\n const _isServer = isServer ?? router.isServer\n if (_isServer) {\n const state = router.stores.__store.get() as RouterState<\n TRouter['routeTree']\n >\n return (opts?.select ? opts.select(state) : state) as UseRouterStateResult<\n TRouter,\n TSelected\n >\n }\n\n // eslint-disable-next-line react-hooks/rules-of-hooks -- condition is static\n return useStore(\n router.stores.__store,\n // eslint-disable-next-line react-hooks/rules-of-hooks -- condition is static\n useStructuralSharing(opts, router),\n ) as UseRouterStateResult<TRouter, TSelected>\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AA4CA,SAAgB,eAKd,MAC0C;CAC1C,MAAM,gBAAgB,UAAmB,EACvC,MAAM,MAAM,WAAW,KAAA,EACzB,CAAC;CACD,MAAM,SAAS,MAAM,UAAU;CAK/B,IADkB,YAAY,OAAO,UACtB;EACb,MAAM,QAAQ,OAAO,OAAO,QAAQ,IAAI;EAGxC,OAAQ,MAAM,SAAS,KAAK,OAAO,KAAK,IAAI;CAI9C;CAGA,OAAO,SACL,OAAO,OAAO,SAEd,qBAAqB,MAAM,MAAM,CACnC;AACF"} |
+1
-1
| { | ||
| "name": "@tanstack/react-router", | ||
| "version": "1.170.15", | ||
| "version": "1.170.16", | ||
| "description": "Modern and scalable routing for React applications", | ||
@@ -5,0 +5,0 @@ "author": "Tanner Linsley", |
+52
-15
@@ -23,4 +23,22 @@ 'use client' | ||
| import { useLayoutEffect } from './utils' | ||
| import type { AnyRoute, RootRouteOptions } from '@tanstack/router-core' | ||
| import type { | ||
| AnyRoute, | ||
| AnyRouteMatch, | ||
| ParsedLocation, | ||
| RootRouteOptions, | ||
| } from '@tanstack/router-core' | ||
| type OutletMatchSelection = [ | ||
| routeId: string | undefined, | ||
| parentGlobalNotFound: boolean, | ||
| ] | ||
| const matchViewFieldsEqual = (a: AnyRouteMatch, b: AnyRouteMatch) => | ||
| a.routeId === b.routeId && a._displayPending === b._displayPending | ||
| const outletMatchSelectionEqual = ( | ||
| a: OutletMatchSelection, | ||
| b: OutletMatchSelection, | ||
| ) => a[0] === b[0] && a[1] === b[1] | ||
| export const Match = React.memo(function MatchImpl({ | ||
@@ -81,3 +99,3 @@ matchId, | ||
| // eslint-disable-next-line react-hooks/rules-of-hooks | ||
| const match = useStore(matchStore, (value) => value) | ||
| const match = useStore(matchStore, (value) => value, matchViewFieldsEqual) | ||
| // eslint-disable-next-line react-hooks/rules-of-hooks | ||
@@ -213,3 +231,3 @@ const matchState = React.useMemo(() => { | ||
| <> | ||
| <OnRendered resetKey={resetKey} /> | ||
| <OnRendered /> | ||
| {router.options.scrollRestoration && (isServer ?? router.isServer) ? ( | ||
@@ -228,3 +246,3 @@ <ScrollRestoration /> | ||
| // (like bad head/link tags, which is common). | ||
| function OnRendered({ resetKey }: { resetKey: number }) { | ||
| function OnRendered() { | ||
| const router = useRouter() | ||
@@ -236,12 +254,27 @@ | ||
| // Track the resolvedLocation as of the last render so that onRendered can | ||
| // report the correct fromLocation. By the time this effect fires, | ||
| // resolvedLocation has already been updated to the new location by | ||
| // Transitioner, so we cannot use router.stores.resolvedLocation.get() | ||
| // directly as the fromLocation. | ||
| // @ts-expect-error -- init to `undefined` but don't write `undefined` to shave bytes | ||
| // eslint-disable-next-line react-hooks/rules-of-hooks | ||
| const prevHrefRef = React.useRef<string | undefined>(undefined) | ||
| const prevResolvedLocationRef = React.useRef< | ||
| ParsedLocation<any> | undefined | ||
| >() | ||
| // eslint-disable-next-line react-hooks/rules-of-hooks | ||
| const renderedLocationKey = useStore( | ||
| router.stores.resolvedLocation, | ||
| (resolvedLocation) => resolvedLocation?.state.__TSR_key, | ||
| ) | ||
| // eslint-disable-next-line react-hooks/rules-of-hooks | ||
| useLayoutEffect(() => { | ||
| const currentHref = router.latestLocation.href | ||
| const currentResolvedLocation = router.stores.resolvedLocation.get() | ||
| const previousResolvedLocation = prevResolvedLocationRef.current | ||
| if ( | ||
| prevHrefRef.current === undefined || | ||
| prevHrefRef.current !== currentHref | ||
| currentResolvedLocation && | ||
| (!previousResolvedLocation || | ||
| previousResolvedLocation.href !== currentResolvedLocation.href) | ||
| ) { | ||
@@ -252,8 +285,8 @@ router.emit({ | ||
| router.stores.location.get(), | ||
| router.stores.resolvedLocation.get(), | ||
| previousResolvedLocation ?? currentResolvedLocation, | ||
| ), | ||
| }) | ||
| prevHrefRef.current = currentHref | ||
| } | ||
| }, [router.latestLocation.state.__TSR_key, resetKey, router]) | ||
| prevResolvedLocationRef.current = currentResolvedLocation | ||
| }, [renderedLocationKey, router]) | ||
@@ -530,6 +563,10 @@ return null | ||
| // eslint-disable-next-line react-hooks/rules-of-hooks | ||
| ;[routeId, parentGlobalNotFound] = useStore(parentMatchStore, (match) => [ | ||
| match?.routeId as string | undefined, | ||
| match?.globalNotFound ?? false, | ||
| ]) | ||
| ;[routeId, parentGlobalNotFound] = useStore( | ||
| parentMatchStore, | ||
| (match): OutletMatchSelection => [ | ||
| match?.routeId as string | undefined, | ||
| match?.globalNotFound ?? false, | ||
| ], | ||
| outletMatchSelectionEqual, | ||
| ) | ||
@@ -536,0 +573,0 @@ // eslint-disable-next-line react-hooks/rules-of-hooks |
+8
-19
@@ -5,6 +5,7 @@ 'use client' | ||
| import { useStore } from '@tanstack/react-store' | ||
| import { replaceEqualDeep, rootRouteId } from '@tanstack/router-core' | ||
| import { rootRouteId } from '@tanstack/router-core' | ||
| import { isServer } from '@tanstack/router-core/isServer' | ||
| import { CatchBoundary, ErrorComponent } from './CatchBoundary' | ||
| import { useRouter } from './useRouter' | ||
| import { useStructuralSharing } from './useMatch' | ||
| import { Transitioner } from './Transitioner' | ||
@@ -238,6 +239,2 @@ import { matchContext } from './matchContext' | ||
| const router = useRouter<TRouter>() | ||
| const previousResult = | ||
| React.useRef<ValidateSelected<TRouter, TSelected, TStructuralSharing>>( | ||
| undefined, | ||
| ) | ||
@@ -254,16 +251,8 @@ if (isServer ?? router.isServer) { | ||
| // eslint-disable-next-line react-hooks/rules-of-hooks | ||
| return useStore(router.stores.matches, (matches) => { | ||
| const selected = opts?.select | ||
| ? opts.select(matches as Array<MakeRouteMatchUnion<TRouter>>) | ||
| : (matches as any) | ||
| if (opts?.structuralSharing ?? router.options.defaultStructuralSharing) { | ||
| const shared = replaceEqualDeep(previousResult.current, selected) | ||
| previousResult.current = shared | ||
| return shared | ||
| } | ||
| return selected | ||
| }) as UseMatchesResult<TRouter, TSelected> | ||
| // eslint-disable-next-line react-hooks/rules-of-hooks -- condition is static | ||
| return useStore( | ||
| router.stores.matches, | ||
| // eslint-disable-next-line react-hooks/rules-of-hooks -- condition is static | ||
| useStructuralSharing(opts, router), | ||
| ) as UseMatchesResult<TRouter, TSelected> | ||
| } | ||
@@ -270,0 +259,0 @@ |
@@ -38,2 +38,8 @@ import { PassThrough } from 'node:stream' | ||
| // A client disconnecting mid-stream is normal operation, not a render | ||
| // failure; don't let React's onError log it as one. | ||
| const isAbortError = (request: Request, error: unknown) => | ||
| (request.signal.aborted && error === request.signal.reason) || | ||
| (error instanceof Error && error.name === 'AbortError') | ||
| export const renderRouterToStream = async ({ | ||
@@ -55,2 +61,7 @@ request, | ||
| progressiveChunkSize: Number.POSITIVE_INFINITY, | ||
| onError: (error, info) => { | ||
| if (!isAbortError(request, error)) { | ||
| console.error('Error in renderToReadableStream:', error, info) | ||
| } | ||
| }, | ||
| }) | ||
@@ -156,3 +167,5 @@ | ||
| onError: (error, info) => { | ||
| console.error('Error in renderToPipeableStream:', error, info) | ||
| if (!isAbortError(request, error)) { | ||
| console.error('Error in renderToPipeableStream:', error, info) | ||
| } | ||
| abortPipeable(error, { defaultError: true }) | ||
@@ -159,0 +172,0 @@ }, |
+6
-19
| 'use client' | ||
| import { useStore } from '@tanstack/react-store' | ||
| import { useRef } from 'react' | ||
| import { replaceEqualDeep } from '@tanstack/router-core' | ||
| import { isServer } from '@tanstack/router-core/isServer' | ||
| import { useRouter } from './useRouter' | ||
| import { useStructuralSharing } from './useMatch' | ||
| import type { | ||
@@ -63,20 +62,8 @@ StructuralSharingOption, | ||
| const previousResult = | ||
| // eslint-disable-next-line react-hooks/rules-of-hooks -- condition is static | ||
| return useStore( | ||
| router.stores.location, | ||
| // eslint-disable-next-line react-hooks/rules-of-hooks -- condition is static | ||
| useRef<ValidateSelected<TRouter, TSelected, TStructuralSharing>>(undefined) | ||
| // eslint-disable-next-line react-hooks/rules-of-hooks -- condition is static | ||
| return useStore(router.stores.location, (location) => { | ||
| const selected = ( | ||
| opts?.select ? opts.select(location as any) : location | ||
| ) as ValidateSelected<TRouter, TSelected, TStructuralSharing> | ||
| if (opts?.structuralSharing ?? router.options.defaultStructuralSharing) { | ||
| const shared = replaceEqualDeep(previousResult.current, selected) | ||
| previousResult.current = shared | ||
| return shared | ||
| } | ||
| return selected | ||
| }) as UseLocationResult<TRouter, TSelected> | ||
| useStructuralSharing(opts, router), | ||
| ) as UseLocationResult<TRouter, TSelected> | ||
| } |
+71
-43
@@ -24,6 +24,47 @@ 'use client' | ||
| const dummyStore = { | ||
| get: () => undefined, | ||
| subscribe: () => ({ unsubscribe: () => {} }), | ||
| get() {}, | ||
| subscribe() { | ||
| return { unsubscribe() {} } | ||
| }, | ||
| } as any | ||
| export function useStructuralSharing< | ||
| TRouter extends AnyRouter, | ||
| TSelected, | ||
| TStructuralSharing extends boolean, | ||
| TStoreSlice, | ||
| TSelectSlice = TStoreSlice, | ||
| >( | ||
| opts: | ||
| | { | ||
| select?: ( | ||
| slice: TSelectSlice, | ||
| ) => ValidateSelected<TRouter, TSelected, TStructuralSharing> | ||
| structuralSharing?: boolean | ||
| } | ||
| | undefined, | ||
| router: TRouter, | ||
| ): ( | ||
| slice: TStoreSlice, | ||
| ) => ValidateSelected<TRouter, TSelected, TStructuralSharing> { | ||
| const previousResult = | ||
| // @ts-expect-error -- init to undefined, but without writing `undefined` to shave bytes | ||
| React.useRef<ValidateSelected<TRouter, TSelected, TStructuralSharing>>() | ||
| return (slice) => { | ||
| const selected = opts?.select | ||
| ? opts.select(slice as unknown as TSelectSlice) | ||
| : (slice as ValidateSelected<TRouter, TSelected, TStructuralSharing>) | ||
| if (opts?.structuralSharing ?? router.options.defaultStructuralSharing) { | ||
| return (previousResult.current = replaceEqualDeep( | ||
| previousResult.current, | ||
| selected, | ||
| )) | ||
| } | ||
| return selected | ||
| } | ||
| } | ||
| export interface UseMatchBaseOptions< | ||
@@ -114,22 +155,19 @@ TRouter extends AnyRouter, | ||
| const key = opts.from ?? nearestMatchId | ||
| const matchStore = key | ||
| ? opts.from | ||
| ? router.stores.getRouteMatchStore(key) | ||
| : router.stores.matchStores.get(key) | ||
| : undefined | ||
| const matchStore = opts.from | ||
| ? router.stores.getRouteMatchStore(opts.from) | ||
| : router.stores.matchStores.get(nearestMatchId!) | ||
| if (isServer ?? router.isServer) { | ||
| const match = matchStore?.get() | ||
| if ((opts.shouldThrow ?? true) && !match) { | ||
| if (process.env.NODE_ENV !== 'production') { | ||
| throw new Error( | ||
| `Invariant failed: Could not find ${opts.from ? `an active match from "${opts.from}"` : 'a nearest match!'}`, | ||
| ) | ||
| if (!match) { | ||
| if (opts.shouldThrow ?? true) { | ||
| if (process.env.NODE_ENV !== 'production') { | ||
| throw new Error( | ||
| `Invariant failed: Could not find ${opts.from ? `an active match from "${opts.from}"` : 'a nearest match!'}`, | ||
| ) | ||
| } | ||
| invariant() | ||
| } | ||
| invariant() | ||
| } | ||
| if (match === undefined) { | ||
| return undefined as any | ||
@@ -141,36 +179,26 @@ } | ||
| const previousResult = | ||
| const selector = | ||
| // eslint-disable-next-line react-hooks/rules-of-hooks -- condition is static | ||
| React.useRef<ValidateSelected<TRouter, TSelected, TStructuralSharing>>( | ||
| undefined, | ||
| ) | ||
| useStructuralSharing(opts, router) | ||
| // eslint-disable-next-line react-hooks/rules-of-hooks -- condition is static | ||
| return useStore(matchStore ?? dummyStore, (match) => { | ||
| if ((opts.shouldThrow ?? true) && !match) { | ||
| if (process.env.NODE_ENV !== 'production') { | ||
| throw new Error( | ||
| `Invariant failed: Could not find ${opts.from ? `an active match from "${opts.from}"` : 'a nearest match!'}`, | ||
| ) | ||
| } | ||
| const matchSelection = useStore(matchStore ?? dummyStore, (match) => | ||
| match ? selector(match as any) : dummyStore, | ||
| ) | ||
| invariant() | ||
| } | ||
| if (matchSelection !== dummyStore) { | ||
| return matchSelection | ||
| } | ||
| if (match === undefined) { | ||
| return undefined | ||
| if (opts.shouldThrow ?? true) { | ||
| if (process.env.NODE_ENV !== 'production') { | ||
| throw new Error( | ||
| `Invariant failed: Could not find ${opts.from ? `an active match from "${opts.from}"` : 'a nearest match!'}`, | ||
| ) | ||
| } | ||
| const selected = ( | ||
| opts.select ? opts.select(match as any) : match | ||
| ) as ValidateSelected<TRouter, TSelected, TStructuralSharing> | ||
| invariant() | ||
| } | ||
| if (opts.structuralSharing ?? router.options.defaultStructuralSharing) { | ||
| const shared = replaceEqualDeep(previousResult.current, selected) | ||
| previousResult.current = shared | ||
| return shared | ||
| } | ||
| return selected | ||
| }) as any | ||
| return undefined as any | ||
| } |
| 'use client' | ||
| import { useStore } from '@tanstack/react-store' | ||
| import { useRef } from 'react' | ||
| import { replaceEqualDeep } from '@tanstack/router-core' | ||
| import { isServer } from '@tanstack/router-core/isServer' | ||
| import { useRouter } from './useRouter' | ||
| import { useStructuralSharing } from './useMatch' | ||
| import type { | ||
@@ -71,21 +70,8 @@ AnyRouter, | ||
| const previousResult = | ||
| // eslint-disable-next-line react-hooks/rules-of-hooks | ||
| useRef<ValidateSelected<TRouter, TSelected, TStructuralSharing>>(undefined) | ||
| // eslint-disable-next-line react-hooks/rules-of-hooks | ||
| return useStore(router.stores.__store, (state) => { | ||
| if (opts?.select) { | ||
| if (opts.structuralSharing ?? router.options.defaultStructuralSharing) { | ||
| const newSlice = replaceEqualDeep( | ||
| previousResult.current, | ||
| opts.select(state), | ||
| ) | ||
| previousResult.current = newSlice | ||
| return newSlice | ||
| } | ||
| return opts.select(state) | ||
| } | ||
| return state | ||
| }) as UseRouterStateResult<TRouter, TSelected> | ||
| // eslint-disable-next-line react-hooks/rules-of-hooks -- condition is static | ||
| return useStore( | ||
| router.stores.__store, | ||
| // eslint-disable-next-line react-hooks/rules-of-hooks -- condition is static | ||
| useStructuralSharing(opts, router), | ||
| ) as UseRouterStateResult<TRouter, TSelected> | ||
| } |
1142810
0.33%14909
-0.05%