@tanstack/react-router
Advanced tools
Comparing version 1.40.0 to 1.41.0
import { DeferredPromise } from './defer.js'; | ||
import * as React from 'react'; | ||
export type AwaitOptions<T> = { | ||
promise: DeferredPromise<T>; | ||
promise: Promise<T>; | ||
}; | ||
export declare function useAwaited<T>({ promise, }: AwaitOptions<T>): [T, DeferredPromise<T>]; | ||
export declare function useAwaited<T>({ promise: _promise, }: AwaitOptions<T>): [T, DeferredPromise<T>]; | ||
export declare function Await<T>(props: AwaitOptions<T> & { | ||
fallback?: React.ReactNode; | ||
children: (result: T) => React.ReactNode; | ||
}): React.JSX.Element; | ||
export declare function ScriptOnce({ className, children, ...rest }: { | ||
children: string; | ||
} & React.HTMLProps<HTMLScriptElement>): React.JSX.Element; | ||
}): import("react/jsx-runtime").JSX.Element; |
@@ -1,2 +0,2 @@ | ||
import { jsx, jsxs, Fragment } from "react/jsx-runtime"; | ||
import { jsx } from "react/jsx-runtime"; | ||
import * as React from "react"; | ||
@@ -6,41 +6,18 @@ import warning from "tiny-warning"; | ||
import { defaultSerializeError } from "./router.js"; | ||
import { isDehydratedDeferred } from "./defer.js"; | ||
import { isServerSideError, defaultDeserializeError } from "./Matches.js"; | ||
import { defer } from "./defer.js"; | ||
import { isServerSideError, defaultDeserializeError } from "./isServerSideError.js"; | ||
function useAwaited({ | ||
promise | ||
promise: _promise | ||
}) { | ||
var _a, _b; | ||
const router = useRouter(); | ||
const state = promise.__deferredState; | ||
if (isDehydratedDeferred(promise) && state.status === "pending") { | ||
const streamedData = window[`__TSR__DEFERRED__${state.uid}`]; | ||
if (streamedData) { | ||
Object.assign(state, router.options.transformer.parse(streamedData)); | ||
} else { | ||
let token = router.registeredDeferredsIds.get(state.uid); | ||
if (!token) { | ||
token = {}; | ||
router.registeredDeferredsIds.set(state.uid, token); | ||
router.registeredDeferreds.set(token, state); | ||
Object.assign(state, { | ||
resolve: () => { | ||
var _a2; | ||
(_a2 = state.__resolvePromise) == null ? void 0 : _a2.call(state); | ||
}, | ||
promise: new Promise((r) => { | ||
state.__resolvePromise = r; | ||
}), | ||
__resolvePromise: () => { | ||
} | ||
}); | ||
} | ||
} | ||
const promise = _promise; | ||
defer(promise); | ||
if (promise.status === "pending") { | ||
throw promise; | ||
} | ||
if (state.status === "pending") { | ||
throw isDehydratedDeferred(promise) ? state.promise : promise; | ||
} | ||
if (state.status === "error") { | ||
if (promise.status === "error") { | ||
if (typeof document !== "undefined") { | ||
if (isServerSideError(state.error)) { | ||
throw (((_a = router.options.errorSerializer) == null ? void 0 : _a.deserialize) ?? defaultDeserializeError)(state.error.data); | ||
if (isServerSideError(promise.error)) { | ||
throw (((_a = router.options.errorSerializer) == null ? void 0 : _a.deserialize) ?? defaultDeserializeError)(promise.error.data); | ||
} else { | ||
@@ -51,7 +28,7 @@ warning( | ||
); | ||
throw state.error; | ||
throw promise.error; | ||
} | ||
} else { | ||
throw { | ||
data: (((_b = router.options.errorSerializer) == null ? void 0 : _b.serialize) ?? defaultSerializeError)(state.error), | ||
data: (((_b = router.options.errorSerializer) == null ? void 0 : _b.serialize) ?? defaultSerializeError)(promise.error), | ||
__isServerError: true | ||
@@ -61,3 +38,3 @@ }; | ||
} | ||
return [promise.__deferredState.data, promise]; | ||
return [promise.data, promise]; | ||
} | ||
@@ -72,43 +49,9 @@ function Await(props) { | ||
function AwaitInner(props) { | ||
const router = useRouter(); | ||
const [data, promise] = useAwaited(props); | ||
const state = promise.__deferredState; | ||
return /* @__PURE__ */ jsxs(Fragment, { children: [ | ||
!isDehydratedDeferred(promise) ? /* @__PURE__ */ jsx( | ||
ScriptOnce, | ||
{ | ||
children: `window.__TSR__DEFERRED__${state.uid} = ${JSON.stringify(router.options.transformer.stringify(state))} | ||
if (window.__TSR__ROUTER__) { | ||
let deferred = window.__TSR__ROUTER__.getDeferred('${state.uid}'); | ||
if (deferred) deferred.resolve(window.__TSR__DEFERRED__${state.uid}); | ||
}` | ||
} | ||
) : null, | ||
props.children(data) | ||
] }); | ||
const [data] = useAwaited(props); | ||
return props.children(data); | ||
} | ||
function ScriptOnce({ | ||
className, | ||
children, | ||
...rest | ||
}) { | ||
return /* @__PURE__ */ jsx( | ||
"script", | ||
{ | ||
...rest, | ||
className: `tsr-script-once ${className || ""}`, | ||
dangerouslySetInnerHTML: { | ||
__html: [ | ||
children, | ||
`document.querySelectorAll('.tsr-script-once').forEach((el) => el.parentElement.removeChild(el));` | ||
].join("\n") | ||
} | ||
} | ||
); | ||
} | ||
export { | ||
Await, | ||
ScriptOnce, | ||
useAwaited | ||
}; | ||
//# sourceMappingURL=awaited.js.map |
@@ -9,5 +9,5 @@ import { ErrorRouteComponent } from './route.js'; | ||
onCatch?: (error: Error, errorInfo: ErrorInfo) => void; | ||
}): React.JSX.Element; | ||
}): import("react/jsx-runtime").JSX.Element; | ||
export declare function ErrorComponent({ error }: { | ||
error: any; | ||
}): React.JSX.Element; | ||
}): import("react/jsx-runtime").JSX.Element; |
@@ -6,4 +6,3 @@ import { defaultSerializeError } from './router.js'; | ||
resolve?: () => void; | ||
promise?: Promise<void>; | ||
__resolvePromise?: () => void; | ||
reject?: () => void; | ||
} & ({ | ||
@@ -21,8 +20,5 @@ status: 'pending'; | ||
}); | ||
export type DeferredPromise<T> = Promise<T> & { | ||
__deferredState: DeferredPromiseState<T>; | ||
}; | ||
export type DeferredPromise<T> = Promise<T> & DeferredPromiseState<T>; | ||
export declare function defer<T>(_promise: Promise<T>, options?: { | ||
serializeError?: typeof defaultSerializeError; | ||
}): DeferredPromise<T>; | ||
export declare function isDehydratedDeferred(obj: any): boolean; |
import { defaultSerializeError } from "./router.js"; | ||
function defer(_promise, options) { | ||
const promise = _promise; | ||
if (!promise.__deferredState) { | ||
promise.__deferredState = { | ||
uid: Math.random().toString(36).slice(2), | ||
if (!promise.status) { | ||
Object.assign(promise, { | ||
status: "pending" | ||
}; | ||
const state = promise.__deferredState; | ||
}); | ||
promise.then((data) => { | ||
state.status = "success"; | ||
state.data = data; | ||
promise.status = "success"; | ||
promise.data = data; | ||
}).catch((error) => { | ||
state.status = "error"; | ||
state.error = { | ||
promise.status = "error"; | ||
promise.error = { | ||
data: ((options == null ? void 0 : options.serializeError) ?? defaultSerializeError)(error), | ||
@@ -23,9 +21,5 @@ __isServerError: true | ||
} | ||
function isDehydratedDeferred(obj) { | ||
return typeof obj === "object" && obj !== null && !(obj instanceof Promise) && !obj.then && "__deferredState" in obj; | ||
} | ||
export { | ||
defer, | ||
isDehydratedDeferred | ||
defer | ||
}; | ||
//# sourceMappingURL=defer.js.map |
export { createHistory, createBrowserHistory, createHashHistory, createMemoryHistory, type BlockerFn, type HistoryLocation, type RouterHistory, type ParsedPath, type HistoryState, } from '@tanstack/history'; | ||
export { default as invariant } from 'tiny-invariant'; | ||
export { default as warning } from 'tiny-warning'; | ||
export { useAwaited, Await, type AwaitOptions, ScriptOnce } from './awaited.js'; | ||
export { defer, isDehydratedDeferred, type DeferredPromiseState, type DeferredPromise, } from './defer.js'; | ||
export { useAwaited, Await, type AwaitOptions } from './awaited.js'; | ||
export { ScriptOnce } from './ScriptOnce.js'; | ||
export { defer, type DeferredPromiseState, type DeferredPromise } from './defer.js'; | ||
export { CatchBoundary, ErrorComponent } from './CatchBoundary.js'; | ||
@@ -12,3 +13,6 @@ export { FileRoute, createFileRoute, FileRouteLoader, LazyRoute, createLazyRoute, createLazyFileRoute, type FileRoutesByPath, type LazyRouteOptions, } from './fileRoute.js'; | ||
export { type ParsedLocation } from './location.js'; | ||
export { matchContext, Matches, Match, Outlet, useMatchRoute, MatchRoute, useMatches, useParentMatches, useChildMatches, isServerSideError, defaultDeserializeError, type RouteMatch, type AnyRouteMatch, type MatchRouteOptions, type UseMatchRouteOptions, type MakeMatchRouteOptions, } from './Matches.js'; | ||
export { Matches, useMatchRoute, MatchRoute, useMatches, useParentMatches, useChildMatches, type RouteMatch, type AnyRouteMatch, type MatchRouteOptions, type UseMatchRouteOptions, type MakeMatchRouteOptions, } from './Matches.js'; | ||
export { matchContext } from './matchContext.js'; | ||
export { Match, Outlet } from './Match.js'; | ||
export { isServerSideError, defaultDeserializeError } from './isServerSideError.js'; | ||
export { useMatch } from './useMatch.js'; | ||
@@ -41,1 +45,2 @@ export { useLoaderDeps } from './useLoaderDeps.js'; | ||
export { type Manifest, type RouterManagedTag } from './manifest.js'; | ||
export { createControlledPromise, type ControlledPromise } from './utils.js'; |
import { createBrowserHistory, createHashHistory, createHistory, createMemoryHistory } from "@tanstack/history"; | ||
import { default as default2 } from "tiny-invariant"; | ||
import { default as default3 } from "tiny-warning"; | ||
import { Await, ScriptOnce, useAwaited } from "./awaited.js"; | ||
import { defer, isDehydratedDeferred } from "./defer.js"; | ||
import { Await, useAwaited } from "./awaited.js"; | ||
import { ScriptOnce } from "./ScriptOnce.js"; | ||
import { defer } from "./defer.js"; | ||
import { CatchBoundary, ErrorComponent } from "./CatchBoundary.js"; | ||
@@ -10,3 +11,6 @@ import { FileRoute, FileRouteLoader, LazyRoute, createFileRoute, createLazyFileRoute, createLazyRoute } from "./fileRoute.js"; | ||
import { Link, createLink, useLinkProps } from "./link.js"; | ||
import { Match, MatchRoute, Matches, Outlet, defaultDeserializeError, isServerSideError, matchContext, useChildMatches, useMatchRoute, useMatches, useParentMatches } from "./Matches.js"; | ||
import { MatchRoute, Matches, useChildMatches, useMatchRoute, useMatches, useParentMatches } from "./Matches.js"; | ||
import { matchContext } from "./matchContext.js"; | ||
import { Match, Outlet } from "./Match.js"; | ||
import { defaultDeserializeError, isServerSideError } from "./isServerSideError.js"; | ||
import { useMatch } from "./useMatch.js"; | ||
@@ -33,3 +37,3 @@ import { useLoaderDeps } from "./useLoaderDeps.js"; | ||
import { useLocation } from "./useLocation.js"; | ||
import { deepEqual, escapeJSON, functionalUpdate, isPlainArray, isPlainObject, pick, replaceEqualDeep, shallow, useLayoutEffect, useStableCallback } from "./utils.js"; | ||
import { createControlledPromise, deepEqual, escapeJSON, functionalUpdate, isPlainArray, isPlainObject, pick, replaceEqualDeep, shallow, useLayoutEffect, useStableCallback } from "./utils.js"; | ||
import { CatchNotFound, DefaultGlobalNotFound, isNotFound, notFound } from "./not-found.js"; | ||
@@ -66,2 +70,3 @@ export { | ||
createBrowserHistory, | ||
createControlledPromise, | ||
createFileRoute, | ||
@@ -95,3 +100,2 @@ createHashHistory, | ||
default2 as invariant, | ||
isDehydratedDeferred, | ||
isNotFound, | ||
@@ -98,0 +102,0 @@ isPlainArray, |
@@ -0,1 +1,2 @@ | ||
"use client"; | ||
import { jsx } from "react/jsx-runtime"; | ||
@@ -2,0 +3,0 @@ import * as React from "react"; |
@@ -7,6 +7,6 @@ import { AnyRouter, RegisteredRouter } from './router.js'; | ||
import * as React from 'react'; | ||
export declare const matchContext: React.Context<string | undefined>; | ||
export interface RouteMatch<TRouteId, TAllParams, TFullSearchSchema, TLoaderData, TAllContext, TRouteContext, TLoaderDeps> { | ||
id: string; | ||
routeId: TRouteId; | ||
index: number; | ||
pathname: string; | ||
@@ -42,7 +42,3 @@ params: TAllParams; | ||
export type AnyRouteMatch = RouteMatch<any, any, any, any, any, any, any>; | ||
export declare function Matches(): React.JSX.Element; | ||
export declare function Match({ matchId }: { | ||
matchId: string; | ||
}): React.JSX.Element; | ||
export declare const Outlet: React.NamedExoticComponent<object>; | ||
export declare function Matches(): import("react/jsx-runtime").JSX.Element; | ||
export interface MatchRouteOptions { | ||
@@ -69,6 +65,1 @@ pending?: boolean; | ||
}): T; | ||
export declare function isServerSideError(error: unknown): error is { | ||
__isServerError: true; | ||
data: Record<string, any>; | ||
}; | ||
export declare function defaultDeserializeError(serializedData: Record<string, any>): any; |
@@ -1,14 +0,11 @@ | ||
import { jsx, Fragment, jsxs } from "react/jsx-runtime"; | ||
import { jsx, jsxs } from "react/jsx-runtime"; | ||
import * as React from "react"; | ||
import invariant from "tiny-invariant"; | ||
import warning from "tiny-warning"; | ||
import { ErrorComponent, CatchBoundary } from "./CatchBoundary.js"; | ||
import { CatchBoundary, ErrorComponent } from "./CatchBoundary.js"; | ||
import { useRouterState } from "./useRouterState.js"; | ||
import { useRouter } from "./useRouter.js"; | ||
import { pick, createControlledPromise } from "./utils.js"; | ||
import { isNotFound, DefaultGlobalNotFound, CatchNotFound } from "./not-found.js"; | ||
import { isRedirect } from "./redirects.js"; | ||
import { Transitioner } from "./Transitioner.js"; | ||
import { rootRouteId } from "./root.js"; | ||
const matchContext = React.createContext(void 0); | ||
import { matchContext } from "./matchContext.js"; | ||
import { Match } from "./Match.js"; | ||
import { SafeFragment } from "./SafeFragment.js"; | ||
function Matches() { | ||
@@ -50,218 +47,2 @@ const router = useRouter(); | ||
} | ||
function SafeFragment(props) { | ||
return /* @__PURE__ */ jsx(Fragment, { children: props.children }); | ||
} | ||
function Match({ matchId }) { | ||
var _a, _b; | ||
const router = useRouter(); | ||
const routeId = useRouterState({ | ||
select: (s) => { | ||
var _a2; | ||
return (_a2 = s.matches.find((d) => d.id === matchId)) == null ? void 0 : _a2.routeId; | ||
} | ||
}); | ||
invariant( | ||
routeId, | ||
`Could not find routeId for matchId "${matchId}". Please file an issue!` | ||
); | ||
const route = router.routesById[routeId]; | ||
const PendingComponent = route.options.pendingComponent ?? router.options.defaultPendingComponent; | ||
const pendingElement = PendingComponent ? /* @__PURE__ */ jsx(PendingComponent, {}) : null; | ||
const routeErrorComponent = route.options.errorComponent ?? router.options.defaultErrorComponent; | ||
const routeOnCatch = route.options.onCatch ?? router.options.defaultOnCatch; | ||
const routeNotFoundComponent = route.isRoot ? ( | ||
// If it's the root route, use the globalNotFound option, with fallback to the notFoundRoute's component | ||
route.options.notFoundComponent ?? ((_a = router.options.notFoundRoute) == null ? void 0 : _a.options.component) | ||
) : route.options.notFoundComponent; | ||
const ResolvedSuspenseBoundary = ( | ||
// If we're on the root route, allow forcefully wrapping in suspense | ||
(!route.isRoot || route.options.wrapInSuspense) && (route.options.wrapInSuspense ?? PendingComponent ?? ((_b = route.options.errorComponent) == null ? void 0 : _b.preload)) ? React.Suspense : SafeFragment | ||
); | ||
const ResolvedCatchBoundary = routeErrorComponent ? CatchBoundary : SafeFragment; | ||
const ResolvedNotFoundBoundary = routeNotFoundComponent ? CatchNotFound : SafeFragment; | ||
const resetKey = useRouterState({ | ||
select: (s) => s.resolvedLocation.state.key | ||
}); | ||
return /* @__PURE__ */ jsx(matchContext.Provider, { value: matchId, children: /* @__PURE__ */ jsx(ResolvedSuspenseBoundary, { fallback: pendingElement, children: /* @__PURE__ */ jsx( | ||
ResolvedCatchBoundary, | ||
{ | ||
getResetKey: () => resetKey, | ||
errorComponent: routeErrorComponent || ErrorComponent, | ||
onCatch: (error, errorInfo) => { | ||
if (isNotFound(error)) throw error; | ||
warning(false, `Error in route match: ${matchId}`); | ||
routeOnCatch == null ? void 0 : routeOnCatch(error, errorInfo); | ||
}, | ||
children: /* @__PURE__ */ jsx( | ||
ResolvedNotFoundBoundary, | ||
{ | ||
fallback: (error) => { | ||
if (!routeNotFoundComponent || error.routeId && error.routeId !== routeId || !error.routeId && !route.isRoot) | ||
throw error; | ||
return React.createElement(routeNotFoundComponent, error); | ||
}, | ||
children: /* @__PURE__ */ jsx(MatchInner, { matchId }) | ||
} | ||
) | ||
} | ||
) }) }); | ||
} | ||
function MatchInner({ matchId }) { | ||
var _a, _b; | ||
const router = useRouter(); | ||
const routeId = useRouterState({ | ||
select: (s) => { | ||
var _a2; | ||
return (_a2 = s.matches.find((d) => d.id === matchId)) == null ? void 0 : _a2.routeId; | ||
} | ||
}); | ||
const route = router.routesById[routeId]; | ||
const match = useRouterState({ | ||
select: (s) => pick(s.matches.find((d) => d.id === matchId), [ | ||
"id", | ||
"status", | ||
"error", | ||
"loadPromise", | ||
"minPendingPromise" | ||
]) | ||
}); | ||
const RouteErrorComponent = (route.options.errorComponent ?? router.options.defaultErrorComponent) || ErrorComponent; | ||
if (match.status === "notFound") { | ||
let error; | ||
if (isServerSideError(match.error)) { | ||
const deserializeError = ((_a = router.options.errorSerializer) == null ? void 0 : _a.deserialize) ?? defaultDeserializeError; | ||
error = deserializeError(match.error.data); | ||
} else { | ||
error = match.error; | ||
} | ||
invariant(isNotFound(error), "Expected a notFound error"); | ||
return renderRouteNotFound(router, route, error); | ||
} | ||
if (match.status === "redirected") { | ||
invariant(isRedirect(match.error), "Expected a redirect error"); | ||
throw match.loadPromise; | ||
} | ||
if (match.status === "error") { | ||
if (router.isServer) { | ||
return /* @__PURE__ */ jsx( | ||
RouteErrorComponent, | ||
{ | ||
error: match.error, | ||
info: { | ||
componentStack: "" | ||
} | ||
} | ||
); | ||
} | ||
if (isServerSideError(match.error)) { | ||
const deserializeError = ((_b = router.options.errorSerializer) == null ? void 0 : _b.deserialize) ?? defaultDeserializeError; | ||
throw deserializeError(match.error.data); | ||
} else { | ||
throw match.error; | ||
} | ||
} | ||
if (match.status === "pending") { | ||
const pendingMinMs = route.options.pendingMinMs ?? router.options.defaultPendingMinMs; | ||
if (pendingMinMs && !match.minPendingPromise) { | ||
match.minPendingPromise = createControlledPromise(); | ||
if (!router.isServer) { | ||
Promise.resolve().then(() => { | ||
router.__store.setState((s) => ({ | ||
...s, | ||
matches: s.matches.map( | ||
(d) => d.id === match.id ? { ...d, minPendingPromise: createControlledPromise() } : d | ||
) | ||
})); | ||
}); | ||
setTimeout(() => { | ||
router.__store.setState((s) => { | ||
return { | ||
...s, | ||
matches: s.matches.map( | ||
(d) => { | ||
var _a2; | ||
return d.id === match.id ? { | ||
...d, | ||
minPendingPromise: ((_a2 = d.minPendingPromise) == null ? void 0 : _a2.resolve(), void 0) | ||
} : d; | ||
} | ||
) | ||
}; | ||
}); | ||
}, pendingMinMs); | ||
} | ||
} | ||
throw match.loadPromise; | ||
} | ||
if (match.status === "success") { | ||
const Comp = route.options.component ?? router.options.defaultComponent; | ||
if (Comp) { | ||
return /* @__PURE__ */ jsx(Comp, {}); | ||
} | ||
return /* @__PURE__ */ jsx(Outlet, {}); | ||
} | ||
invariant( | ||
false, | ||
"Idle routeMatch status encountered during rendering! You should never see this. File an issue!" | ||
); | ||
} | ||
const Outlet = React.memo(function Outlet2() { | ||
const router = useRouter(); | ||
const matchId = React.useContext(matchContext); | ||
const routeId = useRouterState({ | ||
select: (s) => { | ||
var _a; | ||
return (_a = s.matches.find((d) => d.id === matchId)) == null ? void 0 : _a.routeId; | ||
} | ||
}); | ||
const route = router.routesById[routeId]; | ||
const { parentGlobalNotFound } = useRouterState({ | ||
select: (s) => { | ||
const matches = s.matches; | ||
const parentMatch = matches.find((d) => d.id === matchId); | ||
invariant( | ||
parentMatch, | ||
`Could not find parent match for matchId "${matchId}"` | ||
); | ||
return { | ||
parentGlobalNotFound: parentMatch.globalNotFound | ||
}; | ||
} | ||
}); | ||
const childMatchId = useRouterState({ | ||
select: (s) => { | ||
var _a; | ||
const matches = s.matches; | ||
const index = matches.findIndex((d) => d.id === matchId); | ||
return (_a = matches[index + 1]) == null ? void 0 : _a.id; | ||
} | ||
}); | ||
if (parentGlobalNotFound) { | ||
return renderRouteNotFound(router, route, void 0); | ||
} | ||
if (!childMatchId) { | ||
return null; | ||
} | ||
const nextMatch = /* @__PURE__ */ jsx(Match, { matchId: childMatchId }); | ||
const pendingElement = router.options.defaultPendingComponent ? /* @__PURE__ */ jsx(router.options.defaultPendingComponent, {}) : null; | ||
if (matchId === rootRouteId) { | ||
return /* @__PURE__ */ jsx(React.Suspense, { fallback: pendingElement, children: nextMatch }); | ||
} | ||
return nextMatch; | ||
}); | ||
function renderRouteNotFound(router, route, data) { | ||
if (!route.options.notFoundComponent) { | ||
if (router.options.defaultNotFoundComponent) { | ||
return /* @__PURE__ */ jsx(router.options.defaultNotFoundComponent, { data }); | ||
} | ||
if (process.env.NODE_ENV === "development") { | ||
warning( | ||
route.options.notFoundComponent, | ||
`A notFoundError was encountered on the route with ID "${route.id}", but a notFoundComponent option was not configured, nor was a router level defaultNotFoundComponent configured. Consider configuring at least one of these to avoid TanStack Router's overly generic defaultNotFoundComponent (<div>Not Found<div>)` | ||
); | ||
} | ||
return /* @__PURE__ */ jsx(DefaultGlobalNotFound, {}); | ||
} | ||
return /* @__PURE__ */ jsx(route.options.notFoundComponent, { data }); | ||
} | ||
function useMatchRoute() { | ||
@@ -321,27 +102,5 @@ const router = useRouter(); | ||
} | ||
function isServerSideError(error) { | ||
if (!(typeof error === "object" && error && "data" in error)) return false; | ||
if (!("__isServerError" in error && error.__isServerError)) return false; | ||
if (!(typeof error.data === "object" && error.data)) return false; | ||
return error.__isServerError === true; | ||
} | ||
function defaultDeserializeError(serializedData) { | ||
if ("name" in serializedData && "message" in serializedData) { | ||
const error = new Error(serializedData.message); | ||
error.name = serializedData.name; | ||
if (process.env.NODE_ENV === "development") { | ||
error.stack = serializedData.stack; | ||
} | ||
return error; | ||
} | ||
return serializedData.data; | ||
} | ||
export { | ||
Match, | ||
MatchRoute, | ||
Matches, | ||
Outlet, | ||
defaultDeserializeError, | ||
isServerSideError, | ||
matchContext, | ||
useChildMatches, | ||
@@ -348,0 +107,0 @@ useMatchRoute, |
@@ -27,3 +27,3 @@ import { RegisteredRouter } from './router.js'; | ||
children: React.ReactNode; | ||
}): React.JSX.Element; | ||
export declare function DefaultGlobalNotFound(): React.JSX.Element; | ||
}): import("react/jsx-runtime").JSX.Element; | ||
export declare function DefaultGlobalNotFound(): import("react/jsx-runtime").JSX.Element; |
@@ -22,2 +22,2 @@ /** | ||
*/ | ||
export declare function decode(str: any, pfx?: string): {}; | ||
export declare function decode(str: any, pfx?: string): any; |
import { Store, NoInfer } from '@tanstack/react-store'; | ||
import { Manifest } from './manifest.js'; | ||
import { HistoryState, RouterHistory } from '@tanstack/history'; | ||
import { AnyContext, AnyRoute, AnySearchSchema, ErrorRouteComponent, NotFoundRouteComponent, RootRoute, RouteMask, RouteComponent } from './route.js'; | ||
import { AnyContext, AnyRoute, AnySearchSchema, ErrorRouteComponent, NotFoundRouteComponent, RootRoute, RouteComponent, RouteMask } from './route.js'; | ||
import { FullSearchSchema, RouteById, RoutePaths, RoutesById, RoutesByPath } from './routeInfo.js'; | ||
@@ -14,4 +14,2 @@ import { ControlledPromise, NonNullableUpdater, PickAsRequired, Updater } from './utils.js'; | ||
import { NavigateOptions, ResolveRelativePath, ToOptions } from './link.js'; | ||
import { DeferredPromiseState } from './defer.js'; | ||
import { ErrorInfo } from 'react'; | ||
@@ -21,4 +19,6 @@ import type * as React from 'react'; | ||
interface Window { | ||
__TSR_DEHYDRATED__?: { | ||
data: string; | ||
__TSR__?: { | ||
matches: Array<any>; | ||
cleanScripts: () => void; | ||
dehydrated?: any; | ||
}; | ||
@@ -141,3 +141,3 @@ __TSR_ROUTER_CONTEXT__?: React.Context<Router<any, any>>; | ||
*/ | ||
defaultOnCatch?: (error: Error, errorInfo: ErrorInfo) => void; | ||
defaultOnCatch?: (error: Error, errorInfo: React.ErrorInfo) => void; | ||
defaultViewTransition?: boolean; | ||
@@ -351,2 +351,10 @@ /** | ||
manifest?: Manifest; | ||
AfterEachMatch?: (props: { | ||
match: Pick<AnyRouteMatch, 'id' | 'status' | 'error' | 'loadPromise' | 'minPendingPromise'>; | ||
matchIndex: number; | ||
}) => any; | ||
serializeLoaderData?: (data: any, ctx: { | ||
router: AnyRouter; | ||
match: AnyRouteMatch; | ||
}) => any; | ||
__store: Store<RouterState<TRouteTree>>; | ||
@@ -402,5 +410,2 @@ options: PickAsRequired<Omit<RouterOptions<TRouteTree, TTrailingSlashOption, TDehydrated, TSerializedError>, 'transformer'> & { | ||
matchRoute: <TFrom extends RoutePaths<TRouteTree> = "/", TTo extends string = "", TResolved = ResolveRelativePath<TFrom, NoInfer<TTo>>>(location: ToOptions<Router<TRouteTree, TTrailingSlashOption, TDehydrated, TSerializedError>, TFrom, TTo>, opts?: MatchRouteOptions) => false | RouteById<TRouteTree, TResolved>['types']['allParams']; | ||
registeredDeferredsIds: Map<string, {}>; | ||
registeredDeferreds: WeakMap<{}, DeferredPromiseState<any>>; | ||
getDeferred: (uid: string) => DeferredPromiseState<any> | undefined; | ||
dehydrate: () => DehydratedRouter; | ||
@@ -407,0 +412,0 @@ hydrate: (__do_not_use_server_ctx?: string) => Promise<void>; |
@@ -53,3 +53,3 @@ import { createBrowserHistory, createMemoryHistory } from "@tanstack/history"; | ||
if ( | ||
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition | ||
// eslint-disable-next-line ts/no-unnecessary-condition | ||
!this.history || this.options.history && this.options.history !== this.history | ||
@@ -344,2 +344,3 @@ ) { | ||
id: matchId, | ||
index, | ||
routeId: route.id, | ||
@@ -949,3 +950,9 @@ params: routeParams, | ||
} | ||
const loaderData = await loaderPromise; | ||
let loaderData = await loaderPromise; | ||
if (this.serializeLoaderData) { | ||
loaderData = this.serializeLoaderData(loaderData, { | ||
router: this, | ||
match | ||
}); | ||
} | ||
checkLatest(); | ||
@@ -1165,11 +1172,2 @@ handleRedirectAndNotFound(match, loaderData); | ||
}; | ||
this.registeredDeferredsIds = /* @__PURE__ */ new Map(); | ||
this.registeredDeferreds = /* @__PURE__ */ new WeakMap(); | ||
this.getDeferred = (uid) => { | ||
const token = this.registeredDeferredsIds.get(uid); | ||
if (!token) { | ||
return void 0; | ||
} | ||
return this.registeredDeferreds.get(token); | ||
}; | ||
this.dehydrate = () => { | ||
@@ -1180,11 +1178,17 @@ var _a; | ||
state: { | ||
dehydratedMatches: this.state.matches.map((d) => ({ | ||
...pick(d, ["id", "status", "updatedAt", "loaderData"]), | ||
// If an error occurs server-side during SSRing, | ||
// send a small subset of the error to the client | ||
error: d.error ? { | ||
data: pickError(d.error), | ||
__isServerError: true | ||
} : void 0 | ||
})) | ||
dehydratedMatches: this.state.matches.map((d) => { | ||
return { | ||
...pick(d, ["id", "status", "updatedAt"]), | ||
// If an error occurs server-side during SSRing, | ||
// send a small subset of the error to the client | ||
error: d.error ? { | ||
data: pickError(d.error), | ||
__isServerError: true | ||
} : void 0 | ||
// NOTE: We don't send the loader data here, because | ||
// there is a potential that it needs to be streamed. | ||
// Instead, we render it next to the route match in the HTML | ||
// which gives us the potential to stream it via suspense. | ||
}; | ||
}) | ||
}, | ||
@@ -1198,7 +1202,7 @@ manifest: this.manifest | ||
if (typeof document !== "undefined") { | ||
_ctx = (_a = window.__TSR_DEHYDRATED__) == null ? void 0 : _a.data; | ||
_ctx = (_a = window.__TSR__) == null ? void 0 : _a.dehydrated; | ||
} | ||
invariant( | ||
_ctx, | ||
"Expected to find a __TSR_DEHYDRATED__ property on window... but we did not. Please file an issue!" | ||
"Expected to find a dehydrated data on window.__TSR__.dehydrated... but we did not. Please file an issue!" | ||
); | ||
@@ -1205,0 +1209,0 @@ const ctx = this.options.transformer.parse(_ctx); |
@@ -33,4 +33,4 @@ import { NavigateOptions, ToOptions } from './link.js'; | ||
children: React.ReactNode; | ||
}): React.JSX.Element; | ||
export declare function RouterProvider<TRouter extends AnyRouter = RegisteredRouter, TDehydrated extends Record<string, any> = Record<string, any>>({ router, ...rest }: RouterProps<TRouter, TDehydrated>): React.JSX.Element; | ||
}): import("react/jsx-runtime").JSX.Element; | ||
export declare function RouterProvider<TRouter extends AnyRouter = RegisteredRouter, TDehydrated extends Record<string, any> = Record<string, any>>({ router, ...rest }: RouterProps<TRouter, TDehydrated>): import("react/jsx-runtime").JSX.Element; | ||
export declare function getRouteMatch<TRouteTree extends AnyRoute>(state: RouterState<TRouteTree>, id: string): undefined | MakeRouteMatch<TRouteTree>; | ||
@@ -37,0 +37,0 @@ export type RouterProps<TRouter extends AnyRouter = RegisteredRouter, TDehydrated extends Record<string, any> = Record<string, any>> = Omit<RouterOptions<TRouter['routeTree'], NonNullable<TRouter['options']['trailingSlash']>, TDehydrated>, 'context'> & { |
@@ -38,3 +38,4 @@ import * as React from "react"; | ||
useLayoutEffect(() => { | ||
if (window.__TSR_DEHYDRATED__ || mountLoadForRouter.current.router === router && mountLoadForRouter.current.mounted) { | ||
var _a; | ||
if (((_a = window.__TSR__) == null ? void 0 : _a.dehydrated) || mountLoadForRouter.current.router === router && mountLoadForRouter.current.mounted) { | ||
return; | ||
@@ -41,0 +42,0 @@ } |
import * as React from "react"; | ||
import invariant from "tiny-invariant"; | ||
import { useRouterState } from "./useRouterState.js"; | ||
import { matchContext } from "./Matches.js"; | ||
import { matchContext } from "./matchContext.js"; | ||
function useMatch(opts) { | ||
@@ -6,0 +6,0 @@ const nearestMatchId = React.useContext(matchContext); |
@@ -41,3 +41,3 @@ import * as React from 'react'; | ||
export declare function isPlainObject(o: any): boolean; | ||
export declare function isPlainArray(value: unknown): boolean; | ||
export declare function isPlainArray(value: unknown): value is Array<unknown>; | ||
export declare function deepEqual(a: any, b: any, partial?: boolean): boolean; | ||
@@ -64,4 +64,5 @@ export declare function useStableCallback<T extends (...args: Array<any>) => any>(fn: T): T; | ||
status: 'pending' | 'resolved' | 'rejected'; | ||
value?: T; | ||
}; | ||
export declare function createControlledPromise<T>(onResolve?: () => void): ControlledPromise<T>; | ||
export declare function createControlledPromise<T>(onResolve?: (value: T) => void): ControlledPromise<T>; | ||
/** | ||
@@ -68,0 +69,0 @@ * Taken from https://www.developerway.com/posts/implementing-advanced-use-previous-hook#part3 |
@@ -130,6 +130,7 @@ import * as React from "react"; | ||
controlledPromise.status = "pending"; | ||
controlledPromise.resolve = () => { | ||
controlledPromise.resolve = (value) => { | ||
controlledPromise.status = "resolved"; | ||
resolveLoadPromise(); | ||
onResolve == null ? void 0 : onResolve(); | ||
controlledPromise.value = value; | ||
resolveLoadPromise(value); | ||
onResolve == null ? void 0 : onResolve(value); | ||
}; | ||
@@ -136,0 +137,0 @@ controlledPromise.reject = (e) => { |
{ | ||
"name": "@tanstack/react-router", | ||
"version": "1.40.0", | ||
"version": "1.41.0", | ||
"description": "", | ||
@@ -55,3 +55,3 @@ "author": "Tanner Linsley", | ||
"tiny-warning": "^1.0.3", | ||
"@tanstack/history": "1.40.0" | ||
"@tanstack/history": "1.41.0" | ||
}, | ||
@@ -69,6 +69,6 @@ "devDependencies": { | ||
"peerDependencies": { | ||
"react": ">=16.8", | ||
"react-dom": ">=16.8" | ||
"react": ">=18", | ||
"react-dom": ">=18" | ||
}, | ||
"scripts": {} | ||
} |
@@ -6,4 +6,3 @@ import { defaultSerializeError } from './router' | ||
resolve?: () => void | ||
promise?: Promise<void> | ||
__resolvePromise?: () => void | ||
reject?: () => void | ||
} & ( | ||
@@ -26,5 +25,3 @@ | { | ||
export type DeferredPromise<T> = Promise<T> & { | ||
__deferredState: DeferredPromiseState<T> | ||
} | ||
export type DeferredPromise<T> = Promise<T> & DeferredPromiseState<T> | ||
@@ -39,19 +36,15 @@ export function defer<T>( | ||
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition | ||
if (!promise.__deferredState) { | ||
promise.__deferredState = { | ||
uid: Math.random().toString(36).slice(2), | ||
if (!(promise as any).status) { | ||
Object.assign(promise, { | ||
status: 'pending', | ||
} | ||
}) | ||
const state = promise.__deferredState | ||
promise | ||
.then((data) => { | ||
state.status = 'success' as any | ||
state.data = data | ||
promise.status = 'success' as any | ||
promise.data = data | ||
}) | ||
.catch((error) => { | ||
state.status = 'error' as any | ||
state.error = { | ||
promise.status = 'error' as any | ||
;(promise as any).error = { | ||
data: (options?.serializeError ?? defaultSerializeError)(error), | ||
@@ -65,11 +58,1 @@ __isServerError: true, | ||
} | ||
export function isDehydratedDeferred(obj: any): boolean { | ||
return ( | ||
typeof obj === 'object' && | ||
obj !== null && | ||
!(obj instanceof Promise) && | ||
!obj.then && | ||
'__deferredState' in obj | ||
) | ||
} |
@@ -1,3 +0,1 @@ | ||
// @ts-nocheck | ||
// qss has been slightly modified and inlined here for our use cases (and compression's sake). We've included it as a hard dependency for MIT license attribution. | ||
@@ -16,3 +14,3 @@ | ||
*/ | ||
export function encode(obj, pfx?: string) { | ||
export function encode(obj: any, pfx?: string) { | ||
let k, | ||
@@ -48,3 +46,3 @@ i, | ||
*/ | ||
function toValue(mix) { | ||
function toValue(mix: any) { | ||
if (!mix) return '' | ||
@@ -66,5 +64,5 @@ const str = decodeURIComponent(mix) | ||
*/ | ||
export function decode(str, pfx?: string) { | ||
export function decode(str: any, pfx?: string) { | ||
let tmp, k | ||
const out = {}, | ||
const out: any = {}, | ||
arr = (pfx ? str.substr(pfx.length) : str).split('&') | ||
@@ -78,2 +76,3 @@ | ||
if (out[k] !== void 0) { | ||
// @ts-expect-error | ||
out[k] = [].concat(out[k], toValue(value)) | ||
@@ -80,0 +79,0 @@ } else { |
import type { NavigateOptions } from './link' | ||
import type { AnyRoute } from './route' | ||
import type { RoutePaths } from './routeInfo' | ||
@@ -4,0 +3,0 @@ import type { AnyRouter, RegisteredRouter } from './router' |
@@ -709,3 +709,3 @@ import invariant from 'tiny-invariant' | ||
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition | ||
// eslint-disable-next-line ts/no-unnecessary-condition | ||
this.parentRoute = this.options?.getParentRoute?.() | ||
@@ -712,0 +712,0 @@ |
@@ -43,3 +43,3 @@ import * as React from 'react' | ||
// from https://stackoverflow.com/a/53955431 | ||
// eslint-disable-next-line @typescript-eslint/naming-convention | ||
// eslint-disable-next-line ts/naming-convention | ||
export type IsUnion<T, U extends T = T> = ( | ||
@@ -156,3 +156,3 @@ T extends any ? (U extends T ? false : true) : never | ||
for (let i = 0; i < nextSize; i++) { | ||
const key = array ? i : nextItems[i] | ||
const key = array ? i : (nextItems[i] as any) | ||
if ( | ||
@@ -210,3 +210,3 @@ ((!array && prevItems.includes(key)) || array) && | ||
export function isPlainArray(value: unknown) { | ||
export function isPlainArray(value: unknown): value is Array<unknown> { | ||
return Array.isArray(value) && value.length === Object.keys(value).length | ||
@@ -321,9 +321,10 @@ } | ||
status: 'pending' | 'resolved' | 'rejected' | ||
value?: T | ||
} | ||
export function createControlledPromise<T>(onResolve?: () => void) { | ||
let resolveLoadPromise!: () => void | ||
export function createControlledPromise<T>(onResolve?: (value: T) => void) { | ||
let resolveLoadPromise!: (value: T) => void | ||
let rejectLoadPromise!: (value: any) => void | ||
const controlledPromise = new Promise<void>((resolve, reject) => { | ||
const controlledPromise = new Promise<T>((resolve, reject) => { | ||
resolveLoadPromise = resolve | ||
@@ -335,6 +336,7 @@ rejectLoadPromise = reject | ||
controlledPromise.resolve = () => { | ||
controlledPromise.resolve = (value: T) => { | ||
controlledPromise.status = 'resolved' | ||
resolveLoadPromise() | ||
onResolve?.() | ||
controlledPromise.value = value | ||
resolveLoadPromise(value) | ||
onResolve?.(value) | ||
} | ||
@@ -341,0 +343,0 @@ |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
281
16965
1368097
+ Added@tanstack/history@1.41.0(transitive)
- Removed@tanstack/history@1.40.0(transitive)
Updated@tanstack/history@1.41.0