@tanstack/react-router
Advanced tools
@@ -7,4 +7,4 @@ "use client"; | ||
| react = require_runtime.__toESM(react, 1); | ||
| let _tanstack_router_core_isServer = require("@tanstack/router-core/isServer"); | ||
| let react_jsx_runtime = require("react/jsx-runtime"); | ||
| let _tanstack_router_core_isServer = require("@tanstack/router-core/isServer"); | ||
| //#region src/Asset.tsx | ||
@@ -11,0 +11,0 @@ var INLINE_CSS_HYDRATION_ATTR = "data-tsr-inline-css"; |
@@ -8,14 +8,3 @@ "use client"; | ||
| function CatchBoundary(props) { | ||
| const errorComponent = props.errorComponent ?? ErrorComponent; | ||
| return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(CatchBoundaryImpl, { | ||
| getResetKey: props.getResetKey, | ||
| onCatch: props.onCatch, | ||
| children: ({ error, reset }) => { | ||
| if (error) return react.createElement(errorComponent, { | ||
| error, | ||
| reset | ||
| }); | ||
| return props.children; | ||
| } | ||
| }); | ||
| return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(CatchBoundaryImpl, { ...props }); | ||
| } | ||
@@ -26,2 +15,5 @@ var CatchBoundaryImpl = class extends react.Component { | ||
| this.state = { error: null }; | ||
| this.reset = () => { | ||
| this.setState({ error: null }); | ||
| }; | ||
| } | ||
@@ -39,15 +31,11 @@ static getDerivedStateFromProps(props, state) { | ||
| } | ||
| reset() { | ||
| this.setState({ error: null }); | ||
| } | ||
| componentDidCatch(error, errorInfo) { | ||
| if (this.props.onCatch) this.props.onCatch(error, errorInfo); | ||
| this.props.onCatch?.(error, errorInfo); | ||
| } | ||
| render() { | ||
| return this.props.children({ | ||
| error: this.state.error, | ||
| reset: () => { | ||
| this.reset(); | ||
| } | ||
| }); | ||
| const error = this.state.error; | ||
| return error ? react.createElement(this.props.errorComponent ?? ErrorComponent, { | ||
| error, | ||
| reset: this.reset | ||
| }) : this.props.children; | ||
| } | ||
@@ -54,0 +42,0 @@ }; |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"CatchBoundary.cjs","names":[],"sources":["../../src/CatchBoundary.tsx"],"sourcesContent":["'use client'\n\nimport * as React from 'react'\nimport type { ErrorRouteComponent } from './route'\nimport type { ErrorInfo } from 'react'\n\nexport function CatchBoundary(props: {\n getResetKey: () => number | string\n children: React.ReactNode\n errorComponent?: ErrorRouteComponent\n onCatch?: (error: Error, errorInfo: ErrorInfo) => void\n}) {\n const errorComponent = props.errorComponent ?? ErrorComponent\n\n return (\n <CatchBoundaryImpl\n getResetKey={props.getResetKey}\n onCatch={props.onCatch}\n children={({ error, reset }) => {\n if (error) {\n return React.createElement(errorComponent, {\n error,\n reset,\n })\n }\n\n return props.children\n }}\n />\n )\n}\n\nclass CatchBoundaryImpl extends React.Component<{\n getResetKey: () => number | string\n children: (props: {\n error: Error | null\n reset: () => void\n }) => React.ReactNode\n onCatch?: (error: Error, errorInfo: ErrorInfo) => void\n}> {\n state = { error: null } as { error: Error | null; resetKey?: string | number }\n\n static getDerivedStateFromProps(\n props: { getResetKey: () => string | number },\n state: { resetKey?: string | number; error: Error | null },\n ) {\n const resetKey = props.getResetKey()\n\n if (state.error && state.resetKey !== resetKey) {\n return { resetKey, error: null }\n }\n\n return { resetKey }\n }\n static getDerivedStateFromError(error: Error) {\n return { error }\n }\n reset() {\n this.setState({ error: null })\n }\n componentDidCatch(error: Error, errorInfo: ErrorInfo) {\n if (this.props.onCatch) {\n this.props.onCatch(error, errorInfo)\n }\n }\n render() {\n return this.props.children({\n error: this.state.error,\n reset: () => {\n this.reset()\n },\n })\n }\n}\n\nexport function ErrorComponent({ error }: { error: any }) {\n const [show, setShow] = React.useState(process.env.NODE_ENV !== 'production')\n\n return (\n <div style={{ padding: '.5rem', maxWidth: '100%' }}>\n <div style={{ display: 'flex', alignItems: 'center', gap: '.5rem' }}>\n <strong style={{ fontSize: '1rem' }}>Something went wrong!</strong>\n <button\n style={{\n appearance: 'none',\n fontSize: '.6em',\n border: '1px solid currentColor',\n padding: '.1rem .2rem',\n fontWeight: 'bold',\n borderRadius: '.25rem',\n }}\n onClick={() => setShow((d) => !d)}\n >\n {show ? 'Hide Error' : 'Show Error'}\n </button>\n </div>\n <div style={{ height: '.25rem' }} />\n {show ? (\n <div>\n <pre\n style={{\n fontSize: '.7em',\n border: '1px solid red',\n borderRadius: '.25rem',\n padding: '.3rem',\n color: 'red',\n overflow: 'auto',\n }}\n >\n {error.message ? <code>{error.message}</code> : null}\n </pre>\n </div>\n ) : null}\n </div>\n )\n}\n"],"mappings":";;;;;;AAMA,SAAgB,cAAc,OAK3B;CACD,MAAM,iBAAiB,MAAM,kBAAkB;CAE/C,OACE,iBAAA,GAAA,kBAAA,KAAC,mBAAD;EACE,aAAa,MAAM;EACnB,SAAS,MAAM;EACf,WAAW,EAAE,OAAO,YAAY;GAC9B,IAAI,OACF,OAAO,MAAM,cAAc,gBAAgB;IACzC;IACA;GACF,CAAC;GAGH,OAAO,MAAM;EACf;CACD,CAAA;AAEL;AAEA,IAAM,oBAAN,cAAgC,MAAM,UAOnC;;;eACO,EAAE,OAAO,KAAK;;CAEtB,OAAO,yBACL,OACA,OACA;EACA,MAAM,WAAW,MAAM,YAAY;EAEnC,IAAI,MAAM,SAAS,MAAM,aAAa,UACpC,OAAO;GAAE;GAAU,OAAO;EAAK;EAGjC,OAAO,EAAE,SAAS;CACpB;CACA,OAAO,yBAAyB,OAAc;EAC5C,OAAO,EAAE,MAAM;CACjB;CACA,QAAQ;EACN,KAAK,SAAS,EAAE,OAAO,KAAK,CAAC;CAC/B;CACA,kBAAkB,OAAc,WAAsB;EACpD,IAAI,KAAK,MAAM,SACb,KAAK,MAAM,QAAQ,OAAO,SAAS;CAEvC;CACA,SAAS;EACP,OAAO,KAAK,MAAM,SAAS;GACzB,OAAO,KAAK,MAAM;GAClB,aAAa;IACX,KAAK,MAAM;GACb;EACF,CAAC;CACH;AACF;AAEA,SAAgB,eAAe,EAAE,SAAyB;CACxD,MAAM,CAAC,MAAM,WAAW,MAAM,SAAA,QAAA,IAAA,aAAkC,YAAY;CAE5E,OACE,iBAAA,GAAA,kBAAA,MAAC,OAAD;EAAK,OAAO;GAAE,SAAS;GAAS,UAAU;EAAO;YAAjD;GACE,iBAAA,GAAA,kBAAA,MAAC,OAAD;IAAK,OAAO;KAAE,SAAS;KAAQ,YAAY;KAAU,KAAK;IAAQ;cAAlE,CACE,iBAAA,GAAA,kBAAA,KAAC,UAAD;KAAQ,OAAO,EAAE,UAAU,OAAO;eAAG;IAA6B,CAAA,GAClE,iBAAA,GAAA,kBAAA,KAAC,UAAD;KACE,OAAO;MACL,YAAY;MACZ,UAAU;MACV,QAAQ;MACR,SAAS;MACT,YAAY;MACZ,cAAc;KAChB;KACA,eAAe,SAAS,MAAM,CAAC,CAAC;eAE/B,OAAO,eAAe;IACjB,CAAA,CACL;;GACL,iBAAA,GAAA,kBAAA,KAAC,OAAD,EAAK,OAAO,EAAE,QAAQ,SAAS,EAAI,CAAA;GAClC,OACC,iBAAA,GAAA,kBAAA,KAAC,OAAD,EAAA,UACE,iBAAA,GAAA,kBAAA,KAAC,OAAD;IACE,OAAO;KACL,UAAU;KACV,QAAQ;KACR,cAAc;KACd,SAAS;KACT,OAAO;KACP,UAAU;IACZ;cAEC,MAAM,UAAU,iBAAA,GAAA,kBAAA,KAAC,QAAD,EAAA,UAAO,MAAM,QAAc,CAAA,IAAI;GAC7C,CAAA,EACF,CAAA,IACH;EACD;;AAET"} | ||
| {"version":3,"file":"CatchBoundary.cjs","names":[],"sources":["../../src/CatchBoundary.tsx"],"sourcesContent":["'use client'\n\nimport * as React from 'react'\nimport type { ErrorRouteComponent } from './route'\nimport type { ErrorInfo } from 'react'\n\nexport function CatchBoundary(props: {\n getResetKey: () => unknown\n children: React.ReactNode\n errorComponent?: ErrorRouteComponent\n onCatch?: (error: Error, errorInfo: ErrorInfo) => void\n}) {\n return <CatchBoundaryImpl {...props} />\n}\n\nclass CatchBoundaryImpl extends React.Component<{\n getResetKey: () => unknown\n children: React.ReactNode\n errorComponent?: ErrorRouteComponent\n onCatch?: (error: Error, errorInfo: ErrorInfo) => void\n}> {\n state = { error: null } as { error: Error | null; resetKey?: unknown }\n\n static getDerivedStateFromProps(\n props: { getResetKey: () => unknown },\n state: { resetKey?: unknown; error: Error | null },\n ) {\n const resetKey = props.getResetKey()\n\n if (state.error && state.resetKey !== resetKey) {\n return { resetKey, error: null }\n }\n\n return { resetKey }\n }\n static getDerivedStateFromError(error: Error) {\n return { error }\n }\n reset = () => {\n this.setState({ error: null })\n }\n componentDidCatch(error: Error, errorInfo: ErrorInfo) {\n this.props.onCatch?.(error, errorInfo)\n }\n render() {\n const error = this.state.error\n return error\n ? React.createElement(this.props.errorComponent ?? ErrorComponent, {\n error,\n reset: this.reset,\n })\n : this.props.children\n }\n}\n\nexport function ErrorComponent({ error }: { error: any }) {\n const [show, setShow] = React.useState(process.env.NODE_ENV !== 'production')\n\n return (\n <div style={{ padding: '.5rem', maxWidth: '100%' }}>\n <div style={{ display: 'flex', alignItems: 'center', gap: '.5rem' }}>\n <strong style={{ fontSize: '1rem' }}>Something went wrong!</strong>\n <button\n style={{\n appearance: 'none',\n fontSize: '.6em',\n border: '1px solid currentColor',\n padding: '.1rem .2rem',\n fontWeight: 'bold',\n borderRadius: '.25rem',\n }}\n onClick={() => setShow((d) => !d)}\n >\n {show ? 'Hide Error' : 'Show Error'}\n </button>\n </div>\n <div style={{ height: '.25rem' }} />\n {show ? (\n <div>\n <pre\n style={{\n fontSize: '.7em',\n border: '1px solid red',\n borderRadius: '.25rem',\n padding: '.3rem',\n color: 'red',\n overflow: 'auto',\n }}\n >\n {error.message ? <code>{error.message}</code> : null}\n </pre>\n </div>\n ) : null}\n </div>\n )\n}\n"],"mappings":";;;;;;AAMA,SAAgB,cAAc,OAK3B;CACD,OAAO,iBAAA,GAAA,kBAAA,KAAC,mBAAD,EAAmB,GAAI,MAAQ,CAAA;AACxC;AAEA,IAAM,oBAAN,cAAgC,MAAM,UAKnC;;;eACO,EAAE,OAAO,KAAK;qBAiBR;GACZ,KAAK,SAAS,EAAE,OAAO,KAAK,CAAC;EAC/B;;CAjBA,OAAO,yBACL,OACA,OACA;EACA,MAAM,WAAW,MAAM,YAAY;EAEnC,IAAI,MAAM,SAAS,MAAM,aAAa,UACpC,OAAO;GAAE;GAAU,OAAO;EAAK;EAGjC,OAAO,EAAE,SAAS;CACpB;CACA,OAAO,yBAAyB,OAAc;EAC5C,OAAO,EAAE,MAAM;CACjB;CAIA,kBAAkB,OAAc,WAAsB;EACpD,KAAK,MAAM,UAAU,OAAO,SAAS;CACvC;CACA,SAAS;EACP,MAAM,QAAQ,KAAK,MAAM;EACzB,OAAO,QACH,MAAM,cAAc,KAAK,MAAM,kBAAkB,gBAAgB;GAC/D;GACA,OAAO,KAAK;EACd,CAAC,IACD,KAAK,MAAM;CACjB;AACF;AAEA,SAAgB,eAAe,EAAE,SAAyB;CACxD,MAAM,CAAC,MAAM,WAAW,MAAM,SAAA,QAAA,IAAA,aAAkC,YAAY;CAE5E,OACE,iBAAA,GAAA,kBAAA,MAAC,OAAD;EAAK,OAAO;GAAE,SAAS;GAAS,UAAU;EAAO;YAAjD;GACE,iBAAA,GAAA,kBAAA,MAAC,OAAD;IAAK,OAAO;KAAE,SAAS;KAAQ,YAAY;KAAU,KAAK;IAAQ;cAAlE,CACE,iBAAA,GAAA,kBAAA,KAAC,UAAD;KAAQ,OAAO,EAAE,UAAU,OAAO;eAAG;IAA6B,CAAA,GAClE,iBAAA,GAAA,kBAAA,KAAC,UAAD;KACE,OAAO;MACL,YAAY;MACZ,UAAU;MACV,QAAQ;MACR,SAAS;MACT,YAAY;MACZ,cAAc;KAChB;KACA,eAAe,SAAS,MAAM,CAAC,CAAC;eAE/B,OAAO,eAAe;IACjB,CAAA,CACL;;GACL,iBAAA,GAAA,kBAAA,KAAC,OAAD,EAAK,OAAO,EAAE,QAAQ,SAAS,EAAI,CAAA;GAClC,OACC,iBAAA,GAAA,kBAAA,KAAC,OAAD,EAAA,UACE,iBAAA,GAAA,kBAAA,KAAC,OAAD;IACE,OAAO;KACL,UAAU;KACV,QAAQ;KACR,cAAc;KACd,SAAS;KACT,OAAO;KACP,UAAU;IACZ;cAEC,MAAM,UAAU,iBAAA,GAAA,kBAAA,KAAC,QAAD,EAAA,UAAO,MAAM,QAAc,CAAA,IAAI;GAC7C,CAAA,EACF,CAAA,IACH;EACD;;AAET"} |
@@ -5,3 +5,3 @@ import { ErrorRouteComponent } from './route.cjs'; | ||
| export declare function CatchBoundary(props: { | ||
| getResetKey: () => number | string; | ||
| getResetKey: () => unknown; | ||
| children: React.ReactNode; | ||
@@ -8,0 +8,0 @@ errorComponent?: ErrorRouteComponent; |
@@ -25,3 +25,3 @@ "use client"; | ||
| function ClientOnly({ children, fallback = null }) { | ||
| return useHydrated() ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react.default.Fragment, { children }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react.default.Fragment, { children: fallback }); | ||
| return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react.default.Fragment, { children: useHydrated() ? children : fallback }); | ||
| } | ||
@@ -28,0 +28,0 @@ /** |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"ClientOnly.cjs","names":[],"sources":["../../src/ClientOnly.tsx"],"sourcesContent":["'use client'\n\nimport React from 'react'\n\nexport interface ClientOnlyProps {\n /**\n * The children to render when the JS is loaded.\n */\n children: React.ReactNode\n /**\n * The fallback component to render if the JS is not yet loaded.\n */\n fallback?: React.ReactNode\n}\n\n/**\n * Render the children only after the JS has loaded client-side. Use an optional\n * fallback component if the JS is not yet loaded.\n *\n * @example\n * Render a Chart component if JS loads, renders a simple FakeChart\n * component server-side or if there is no JS. The FakeChart can have only the\n * UI without the behavior or be a loading spinner or skeleton.\n *\n * ```tsx\n * return (\n * <ClientOnly fallback={<FakeChart />}>\n * <Chart />\n * </ClientOnly>\n * )\n * ```\n */\nexport function ClientOnly({ children, fallback = null }: ClientOnlyProps) {\n return useHydrated() ? (\n <React.Fragment>{children}</React.Fragment>\n ) : (\n <React.Fragment>{fallback}</React.Fragment>\n )\n}\n\n/**\n * Return a boolean indicating if the JS has been hydrated already.\n * When doing Server-Side Rendering, the result will always be false.\n * When doing Client-Side Rendering, the result will always be false on the\n * first render and true from then on. Even if a new component renders it will\n * always start with true.\n *\n * @example\n * ```tsx\n * // Disable a button that needs JS to work.\n * let hydrated = useHydrated()\n * return (\n * <button type=\"button\" disabled={!hydrated} onClick={doSomethingCustom}>\n * Click me\n * </button>\n * )\n * ```\n * @returns True if the JS has been hydrated already, false otherwise.\n */\nexport function useHydrated(): boolean {\n return React.useSyncExternalStore(\n subscribe,\n () => true,\n () => false,\n )\n}\n\nfunction subscribe() {\n return () => {\n // noop\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;AAgCA,SAAgB,WAAW,EAAE,UAAU,WAAW,QAAyB;CACzE,OAAO,YAAY,IACjB,iBAAA,GAAA,kBAAA,KAAC,MAAA,QAAM,UAAP,EAAiB,SAAyB,CAAA,IAE1C,iBAAA,GAAA,kBAAA,KAAC,MAAA,QAAM,UAAP,EAAA,UAAiB,SAAyB,CAAA;AAE9C;;;;;;;;;;;;;;;;;;;;AAqBA,SAAgB,cAAuB;CACrC,OAAO,MAAA,QAAM,qBACX,iBACM,YACA,KACR;AACF;AAEA,SAAS,YAAY;CACnB,aAAa,CAEb;AACF"} | ||
| {"version":3,"file":"ClientOnly.cjs","names":[],"sources":["../../src/ClientOnly.tsx"],"sourcesContent":["'use client'\n\nimport React from 'react'\n\nexport interface ClientOnlyProps {\n /**\n * The children to render when the JS is loaded.\n */\n children: React.ReactNode\n /**\n * The fallback component to render if the JS is not yet loaded.\n */\n fallback?: React.ReactNode\n}\n\n/**\n * Render the children only after the JS has loaded client-side. Use an optional\n * fallback component if the JS is not yet loaded.\n *\n * @example\n * Render a Chart component if JS loads, renders a simple FakeChart\n * component server-side or if there is no JS. The FakeChart can have only the\n * UI without the behavior or be a loading spinner or skeleton.\n *\n * ```tsx\n * return (\n * <ClientOnly fallback={<FakeChart />}>\n * <Chart />\n * </ClientOnly>\n * )\n * ```\n */\nexport function ClientOnly({ children, fallback = null }: ClientOnlyProps) {\n return <React.Fragment>{useHydrated() ? children : fallback}</React.Fragment>\n}\n\n/**\n * Return a boolean indicating if the JS has been hydrated already.\n * When doing Server-Side Rendering, the result will always be false.\n * When doing Client-Side Rendering, the result will always be false on the\n * first render and true from then on. Even if a new component renders it will\n * always start with true.\n *\n * @example\n * ```tsx\n * // Disable a button that needs JS to work.\n * let hydrated = useHydrated()\n * return (\n * <button type=\"button\" disabled={!hydrated} onClick={doSomethingCustom}>\n * Click me\n * </button>\n * )\n * ```\n * @returns True if the JS has been hydrated already, false otherwise.\n */\nexport function useHydrated(): boolean {\n return React.useSyncExternalStore(\n subscribe,\n () => true,\n () => false,\n )\n}\n\nfunction subscribe() {\n return () => {\n // noop\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;AAgCA,SAAgB,WAAW,EAAE,UAAU,WAAW,QAAyB;CACzE,OAAO,iBAAA,GAAA,kBAAA,KAAC,MAAA,QAAM,UAAP,EAAA,UAAiB,YAAY,IAAI,WAAW,SAAyB,CAAA;AAC9E;;;;;;;;;;;;;;;;;;;;AAqBA,SAAgB,cAAuB;CACrC,OAAO,MAAA,QAAM,qBACX,iBACM,YACA,KACR;AACF;AAEA,SAAS,YAAY;CACnB,aAAa,CAEb;AACF"} |
@@ -6,6 +6,7 @@ const require_runtime = require("./_virtual/_rolldown/runtime.cjs"); | ||
| react = require_runtime.__toESM(react, 1); | ||
| let _tanstack_router_core_isServer = require("@tanstack/router-core/isServer"); | ||
| let _tanstack_react_store = require("@tanstack/react-store"); | ||
| let _tanstack_router_core_isServer = require("@tanstack/router-core/isServer"); | ||
| //#region src/headContentUtils.tsx | ||
| function buildTagsFromMatches(router, nonce, matches, assetCrossOrigin) { | ||
| matches = (0, _tanstack_router_core._getAssetMatches)(matches); | ||
| const routeMeta = matches.map((match) => match.meta).filter((meta) => meta !== void 0); | ||
@@ -129,3 +130,3 @@ const resultMeta = []; | ||
| /** | ||
| * Build the list of head/link/meta/script tags to render for active matches. | ||
| * Build the head/link/meta/script tags from the renderable presented prefix. | ||
| * Used internally by `HeadContent`. | ||
@@ -137,136 +138,8 @@ */ | ||
| if (_tanstack_router_core_isServer.isServer ?? router.isServer) return buildTagsFromMatches(router, nonce, router.stores.matches.get(), assetCrossOrigin); | ||
| const routeMeta = (0, _tanstack_react_store.useStore)(router.stores.matches, (matches) => { | ||
| return matches.map((match) => match.meta).filter((meta) => meta !== void 0); | ||
| }, _tanstack_router_core.deepEqual); | ||
| const meta = react.useMemo(() => { | ||
| const resultMeta = []; | ||
| const metaByAttribute = {}; | ||
| let title; | ||
| for (let i = routeMeta.length - 1; i >= 0; i--) { | ||
| const metas = routeMeta[i]; | ||
| for (let j = metas.length - 1; j >= 0; j--) { | ||
| const m = metas[j]; | ||
| if (!m) continue; | ||
| if (m.title) { | ||
| if (!title) title = { | ||
| tag: "title", | ||
| children: m.title | ||
| }; | ||
| } else if ("script:ld+json" in m) try { | ||
| const json = JSON.stringify(m["script:ld+json"]); | ||
| resultMeta.push({ | ||
| tag: "script", | ||
| attrs: { type: "application/ld+json" }, | ||
| children: (0, _tanstack_router_core.escapeHtml)(json) | ||
| }); | ||
| } catch {} | ||
| else { | ||
| const attribute = m.name ?? m.property; | ||
| if (attribute) if (metaByAttribute[attribute]) continue; | ||
| else metaByAttribute[attribute] = true; | ||
| resultMeta.push({ | ||
| tag: "meta", | ||
| attrs: { | ||
| ...m, | ||
| nonce | ||
| } | ||
| }); | ||
| } | ||
| } | ||
| } | ||
| if (title) resultMeta.push(title); | ||
| if (nonce) resultMeta.push({ | ||
| tag: "meta", | ||
| attrs: { | ||
| property: "csp-nonce", | ||
| content: nonce | ||
| } | ||
| }); | ||
| resultMeta.reverse(); | ||
| return resultMeta; | ||
| }, [routeMeta, nonce]); | ||
| const links = (0, _tanstack_react_store.useStore)(router.stores.matches, (matches) => { | ||
| return matches.flatMap((match) => match.links ?? []).filter((link) => link !== void 0).map((link) => ({ | ||
| tag: "link", | ||
| attrs: { | ||
| ...link, | ||
| nonce | ||
| } | ||
| })); | ||
| }, _tanstack_router_core.deepEqual); | ||
| const manifestCssTags = (0, _tanstack_react_store.useStore)(router.stores.matches, (matches) => { | ||
| const manifest = router.ssr?.manifest; | ||
| const tags = []; | ||
| if (!manifest) return tags; | ||
| matches.forEach((match) => { | ||
| manifest.routes[match.routeId]?.css?.forEach((link) => { | ||
| const resolvedLink = (0, _tanstack_router_core.resolveManifestCssLink)(link); | ||
| tags.push({ | ||
| tag: "link", | ||
| attrs: { | ||
| rel: "stylesheet", | ||
| ...resolvedLink, | ||
| crossOrigin: (0, _tanstack_router_core.getAssetCrossOrigin)(assetCrossOrigin, "stylesheet") ?? resolvedLink.crossOrigin, | ||
| suppressHydrationWarning: true, | ||
| nonce | ||
| } | ||
| }); | ||
| }); | ||
| }); | ||
| if (manifest.inlineStyle) tags.push({ | ||
| tag: "style", | ||
| attrs: { | ||
| ...manifest.inlineStyle.attrs, | ||
| nonce | ||
| }, | ||
| children: manifest.inlineStyle.children, | ||
| inlineCss: true | ||
| }); | ||
| return tags; | ||
| }, _tanstack_router_core.deepEqual); | ||
| const preloadLinks = (0, _tanstack_react_store.useStore)(router.stores.matches, (matches) => { | ||
| const preloadLinks = []; | ||
| const manifest = router.ssr?.manifest; | ||
| if (!manifest) return preloadLinks; | ||
| matches.forEach((match) => { | ||
| manifest.routes[match.routeId]?.preloads?.forEach((preload) => { | ||
| preloadLinks.push({ | ||
| tag: "link", | ||
| attrs: { | ||
| ...(0, _tanstack_router_core.getScriptPreloadAttrs)(manifest, preload, assetCrossOrigin), | ||
| nonce | ||
| } | ||
| }); | ||
| }); | ||
| }); | ||
| return preloadLinks; | ||
| }, _tanstack_router_core.deepEqual); | ||
| const styles = (0, _tanstack_react_store.useStore)(router.stores.matches, (matches) => { | ||
| return matches.flatMap((match) => match.styles ?? []).filter((style) => style !== void 0).map(({ children, ...attrs }) => ({ | ||
| tag: "style", | ||
| attrs: { | ||
| ...attrs, | ||
| nonce | ||
| }, | ||
| children | ||
| })); | ||
| }, _tanstack_router_core.deepEqual); | ||
| const headScripts = (0, _tanstack_react_store.useStore)(router.stores.matches, (matches) => { | ||
| return matches.flatMap((match) => match.headScripts ?? []).filter((script) => script !== void 0).map(({ children, ...script }) => ({ | ||
| tag: "script", | ||
| attrs: { | ||
| ...script, | ||
| nonce | ||
| }, | ||
| children | ||
| })); | ||
| }, _tanstack_router_core.deepEqual); | ||
| const tags = []; | ||
| (0, _tanstack_router_core.appendUniqueUserTags)(tags, meta); | ||
| tags.push(...preloadLinks); | ||
| (0, _tanstack_router_core.appendUniqueUserTags)(tags, links); | ||
| tags.push(...manifestCssTags); | ||
| (0, _tanstack_router_core.appendUniqueUserTags)(tags, styles); | ||
| (0, _tanstack_router_core.appendUniqueUserTags)(tags, headScripts); | ||
| return tags; | ||
| const selectTags = react.useCallback((matches) => buildTagsFromMatches(router, nonce, matches, assetCrossOrigin), [ | ||
| assetCrossOrigin, | ||
| nonce, | ||
| router | ||
| ]); | ||
| return (0, _tanstack_react_store.useStore)(router.stores.matches, selectTags, _tanstack_router_core.deepEqual); | ||
| }; | ||
@@ -273,0 +146,0 @@ //#endregion |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"headContentUtils.cjs","names":[],"sources":["../../src/headContentUtils.tsx"],"sourcesContent":["import * as React from 'react'\nimport { useStore } from '@tanstack/react-store'\nimport {\n appendUniqueUserTags,\n deepEqual,\n escapeHtml,\n getAssetCrossOrigin,\n getScriptPreloadAttrs,\n resolveManifestCssLink,\n} from '@tanstack/router-core'\nimport { isServer } from '@tanstack/router-core/isServer'\nimport { useRouter } from './useRouter'\nimport type {\n AnyRouteMatch,\n AssetCrossOriginConfig,\n RouterManagedTag,\n} from '@tanstack/router-core'\n\nfunction buildTagsFromMatches(\n router: ReturnType<typeof useRouter>,\n nonce: string | undefined,\n matches: Array<AnyRouteMatch>,\n assetCrossOrigin?: AssetCrossOriginConfig,\n): Array<RouterManagedTag> {\n const routeMeta = matches\n .map((match) => match.meta)\n .filter((meta) => meta !== undefined)\n\n const resultMeta: Array<RouterManagedTag> = []\n const metaByAttribute: Record<string, true> = {}\n let title: RouterManagedTag | undefined\n for (let i = routeMeta.length - 1; i >= 0; i--) {\n const metas = routeMeta[i]!\n for (let j = metas.length - 1; j >= 0; j--) {\n const m = metas[j]\n if (!m) continue\n\n if (m.title) {\n if (!title) {\n title = {\n tag: 'title',\n children: m.title,\n }\n }\n } else if ('script:ld+json' in m) {\n try {\n const json = JSON.stringify(m['script:ld+json'])\n resultMeta.push({\n tag: 'script',\n attrs: {\n type: 'application/ld+json',\n },\n children: escapeHtml(json),\n })\n } catch {\n // Skip invalid JSON-LD objects\n }\n } else {\n const attribute = m.name ?? m.property\n if (attribute) {\n if (metaByAttribute[attribute]) {\n continue\n } else {\n metaByAttribute[attribute] = true\n }\n }\n\n resultMeta.push({\n tag: 'meta',\n attrs: {\n ...m,\n nonce,\n },\n })\n }\n }\n }\n\n if (title) {\n resultMeta.push(title)\n }\n\n if (nonce) {\n resultMeta.push({\n tag: 'meta',\n attrs: {\n property: 'csp-nonce',\n content: nonce,\n },\n })\n }\n resultMeta.reverse()\n\n const constructedLinks = matches\n .flatMap((match) => match.links ?? [])\n .filter((link) => link !== undefined)\n .map((link) => ({\n tag: 'link',\n attrs: {\n ...link,\n nonce,\n },\n })) satisfies Array<RouterManagedTag>\n\n const manifest = router.ssr?.manifest\n const manifestCssTags: Array<RouterManagedTag> = []\n if (manifest) {\n matches.forEach((match) => {\n const css = manifest.routes[match.routeId]?.css\n css?.forEach((link) => {\n const resolvedLink = resolveManifestCssLink(link)\n manifestCssTags.push({\n tag: 'link',\n attrs: {\n rel: 'stylesheet',\n ...resolvedLink,\n crossOrigin:\n getAssetCrossOrigin(assetCrossOrigin, 'stylesheet') ??\n resolvedLink.crossOrigin,\n suppressHydrationWarning: true,\n nonce,\n },\n })\n })\n })\n\n if (manifest.inlineStyle) {\n manifestCssTags.push({\n tag: 'style',\n attrs: {\n ...manifest.inlineStyle.attrs,\n nonce,\n },\n children: manifest.inlineStyle.children,\n inlineCss: true,\n })\n }\n }\n\n const preloadLinks: Array<RouterManagedTag> = []\n if (manifest) {\n matches.forEach((match) => {\n manifest.routes[match.routeId]?.preloads?.forEach((preload) => {\n preloadLinks.push({\n tag: 'link',\n attrs: {\n ...getScriptPreloadAttrs(manifest, preload, assetCrossOrigin),\n nonce,\n },\n })\n })\n })\n }\n\n const styles = matches\n .flatMap((match) => match.styles ?? [])\n .filter((style) => style !== undefined)\n .map(({ children, ...attrs }) => ({\n tag: 'style',\n attrs: {\n ...attrs,\n nonce,\n },\n children: children as string | undefined,\n })) satisfies Array<RouterManagedTag>\n\n const headScripts = matches\n .flatMap((match) => match.headScripts ?? [])\n .filter((script) => script !== undefined)\n .map(({ children, ...script }) => ({\n tag: 'script',\n attrs: {\n ...script,\n nonce,\n },\n children: children as string | undefined,\n })) satisfies Array<RouterManagedTag>\n\n const tags: Array<RouterManagedTag> = []\n appendUniqueUserTags(tags, resultMeta)\n tags.push(...preloadLinks)\n appendUniqueUserTags(tags, constructedLinks)\n tags.push(...manifestCssTags)\n appendUniqueUserTags(tags, styles)\n appendUniqueUserTags(tags, headScripts)\n return tags\n}\n\n/**\n * Build the list of head/link/meta/script tags to render for active matches.\n * Used internally by `HeadContent`.\n */\nexport const useTags = (assetCrossOrigin?: AssetCrossOriginConfig) => {\n const router = useRouter()\n const nonce = router.options.ssr?.nonce\n\n if (isServer ?? router.isServer) {\n return buildTagsFromMatches(\n router,\n nonce,\n router.stores.matches.get(),\n assetCrossOrigin,\n )\n }\n\n // eslint-disable-next-line react-hooks/rules-of-hooks -- condition is static\n const routeMeta = useStore(\n router.stores.matches,\n (matches) => {\n return matches\n .map((match) => match.meta)\n .filter((meta) => meta !== undefined)\n },\n deepEqual,\n )\n\n // eslint-disable-next-line react-hooks/rules-of-hooks -- condition is static\n const meta: Array<RouterManagedTag> = React.useMemo(() => {\n const resultMeta: Array<RouterManagedTag> = []\n const metaByAttribute: Record<string, true> = {}\n let title: RouterManagedTag | undefined\n for (let i = routeMeta.length - 1; i >= 0; i--) {\n const metas = routeMeta[i]!\n for (let j = metas.length - 1; j >= 0; j--) {\n const m = metas[j]\n if (!m) continue\n\n if (m.title) {\n if (!title) {\n title = {\n tag: 'title',\n children: m.title,\n }\n }\n } else if ('script:ld+json' in m) {\n // Handle JSON-LD structured data\n // Content is HTML-escaped to prevent XSS when injected via dangerouslySetInnerHTML\n try {\n const json = JSON.stringify(m['script:ld+json'])\n resultMeta.push({\n tag: 'script',\n attrs: {\n type: 'application/ld+json',\n },\n children: escapeHtml(json),\n })\n } catch {\n // Skip invalid JSON-LD objects\n }\n } else {\n const attribute = m.name ?? m.property\n if (attribute) {\n if (metaByAttribute[attribute]) {\n continue\n } else {\n metaByAttribute[attribute] = true\n }\n }\n\n resultMeta.push({\n tag: 'meta',\n attrs: {\n ...m,\n nonce,\n },\n })\n }\n }\n }\n\n if (title) {\n resultMeta.push(title)\n }\n\n if (nonce) {\n resultMeta.push({\n tag: 'meta',\n attrs: {\n property: 'csp-nonce',\n content: nonce,\n },\n })\n }\n resultMeta.reverse()\n\n return resultMeta\n }, [routeMeta, nonce])\n\n // eslint-disable-next-line react-hooks/rules-of-hooks -- condition is static\n const links = useStore(\n router.stores.matches,\n (matches) => {\n const constructed = matches\n .flatMap((match) => match.links ?? [])\n .filter((link) => link !== undefined)\n .map((link) => ({\n tag: 'link',\n attrs: {\n ...link,\n nonce,\n },\n })) satisfies Array<RouterManagedTag>\n\n return constructed\n },\n deepEqual,\n )\n\n // eslint-disable-next-line react-hooks/rules-of-hooks -- condition is static\n const manifestCssTags = useStore(\n router.stores.matches,\n (matches) => {\n const manifest = router.ssr?.manifest\n const tags: Array<RouterManagedTag> = []\n\n if (!manifest) {\n return tags\n }\n\n matches.forEach((match) => {\n manifest.routes[match.routeId]?.css?.forEach((link) => {\n const resolvedLink = resolveManifestCssLink(link)\n tags.push({\n tag: 'link',\n attrs: {\n rel: 'stylesheet',\n ...resolvedLink,\n crossOrigin:\n getAssetCrossOrigin(assetCrossOrigin, 'stylesheet') ??\n resolvedLink.crossOrigin,\n suppressHydrationWarning: true,\n nonce,\n },\n })\n })\n })\n\n if (manifest.inlineStyle) {\n tags.push({\n tag: 'style',\n attrs: {\n ...manifest.inlineStyle.attrs,\n nonce,\n },\n children: manifest.inlineStyle.children,\n inlineCss: true,\n })\n }\n\n return tags\n },\n deepEqual,\n )\n\n // eslint-disable-next-line react-hooks/rules-of-hooks -- condition is static\n const preloadLinks = useStore(\n router.stores.matches,\n (matches) => {\n const preloadLinks: Array<RouterManagedTag> = []\n const manifest = router.ssr?.manifest\n\n if (!manifest) {\n return preloadLinks\n }\n\n matches.forEach((match) => {\n manifest.routes[match.routeId]?.preloads?.forEach((preload) => {\n preloadLinks.push({\n tag: 'link',\n attrs: {\n ...getScriptPreloadAttrs(manifest, preload, assetCrossOrigin),\n nonce,\n },\n })\n })\n })\n\n return preloadLinks\n },\n deepEqual,\n )\n\n // eslint-disable-next-line react-hooks/rules-of-hooks -- condition is static\n const styles = useStore(\n router.stores.matches,\n (matches) => {\n return matches\n .flatMap((match) => match.styles ?? [])\n .filter((style) => style !== undefined)\n .map(({ children, ...attrs }) => ({\n tag: 'style',\n attrs: {\n ...attrs,\n nonce,\n },\n children: children as string | undefined,\n })) satisfies Array<RouterManagedTag>\n },\n deepEqual,\n )\n\n // eslint-disable-next-line react-hooks/rules-of-hooks -- condition is static\n const headScripts: Array<RouterManagedTag> = useStore(\n router.stores.matches,\n (matches) => {\n return matches\n .flatMap((match) => match.headScripts ?? [])\n .filter((script) => script !== undefined)\n .map(({ children, ...script }) => ({\n tag: 'script',\n attrs: {\n ...script,\n nonce,\n },\n children: children as string | undefined,\n })) satisfies Array<RouterManagedTag>\n },\n deepEqual,\n )\n\n const tags: Array<RouterManagedTag> = []\n appendUniqueUserTags(tags, meta)\n tags.push(...preloadLinks)\n appendUniqueUserTags(tags, links)\n tags.push(...manifestCssTags)\n appendUniqueUserTags(tags, styles)\n appendUniqueUserTags(tags, headScripts)\n return tags\n}\n"],"mappings":"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"} | ||
| {"version":3,"file":"headContentUtils.cjs","names":[],"sources":["../../src/headContentUtils.tsx"],"sourcesContent":["import * as React from 'react'\nimport { useStore } from '@tanstack/react-store'\nimport {\n _getAssetMatches,\n appendUniqueUserTags,\n deepEqual,\n escapeHtml,\n getAssetCrossOrigin,\n getScriptPreloadAttrs,\n resolveManifestCssLink,\n} from '@tanstack/router-core'\nimport { isServer } from '@tanstack/router-core/isServer'\nimport { useRouter } from './useRouter'\nimport type {\n AnyRouteMatch,\n AssetCrossOriginConfig,\n RouterManagedTag,\n} from '@tanstack/router-core'\n\nfunction buildTagsFromMatches(\n router: ReturnType<typeof useRouter>,\n nonce: string | undefined,\n matches: Array<AnyRouteMatch>,\n assetCrossOrigin?: AssetCrossOriginConfig,\n): Array<RouterManagedTag> {\n matches = _getAssetMatches(matches)\n const routeMeta = matches\n .map((match) => match.meta)\n .filter((meta) => meta !== undefined)\n\n const resultMeta: Array<RouterManagedTag> = []\n const metaByAttribute: Record<string, true> = {}\n let title: RouterManagedTag | undefined\n for (let i = routeMeta.length - 1; i >= 0; i--) {\n const metas = routeMeta[i]!\n for (let j = metas.length - 1; j >= 0; j--) {\n const m = metas[j]\n if (!m) continue\n\n if (m.title) {\n if (!title) {\n title = {\n tag: 'title',\n children: m.title,\n }\n }\n } else if ('script:ld+json' in m) {\n try {\n const json = JSON.stringify(m['script:ld+json'])\n resultMeta.push({\n tag: 'script',\n attrs: {\n type: 'application/ld+json',\n },\n children: escapeHtml(json),\n })\n } catch {\n // Skip invalid JSON-LD objects\n }\n } else {\n const attribute = m.name ?? m.property\n if (attribute) {\n if (metaByAttribute[attribute]) {\n continue\n } else {\n metaByAttribute[attribute] = true\n }\n }\n\n resultMeta.push({\n tag: 'meta',\n attrs: {\n ...m,\n nonce,\n },\n })\n }\n }\n }\n\n if (title) {\n resultMeta.push(title)\n }\n\n if (nonce) {\n resultMeta.push({\n tag: 'meta',\n attrs: {\n property: 'csp-nonce',\n content: nonce,\n },\n })\n }\n resultMeta.reverse()\n\n const constructedLinks = matches\n .flatMap((match) => match.links ?? [])\n .filter((link) => link !== undefined)\n .map((link) => ({\n tag: 'link',\n attrs: {\n ...link,\n nonce,\n },\n })) satisfies Array<RouterManagedTag>\n\n const manifest = router.ssr?.manifest\n const manifestCssTags: Array<RouterManagedTag> = []\n if (manifest) {\n matches.forEach((match) => {\n const css = manifest.routes[match.routeId]?.css\n css?.forEach((link) => {\n const resolvedLink = resolveManifestCssLink(link)\n manifestCssTags.push({\n tag: 'link',\n attrs: {\n rel: 'stylesheet',\n ...resolvedLink,\n crossOrigin:\n getAssetCrossOrigin(assetCrossOrigin, 'stylesheet') ??\n resolvedLink.crossOrigin,\n suppressHydrationWarning: true,\n nonce,\n },\n })\n })\n })\n\n if (manifest.inlineStyle) {\n manifestCssTags.push({\n tag: 'style',\n attrs: {\n ...manifest.inlineStyle.attrs,\n nonce,\n },\n children: manifest.inlineStyle.children,\n inlineCss: true,\n })\n }\n }\n\n const preloadLinks: Array<RouterManagedTag> = []\n if (manifest) {\n matches.forEach((match) => {\n manifest.routes[match.routeId]?.preloads?.forEach((preload) => {\n preloadLinks.push({\n tag: 'link',\n attrs: {\n ...getScriptPreloadAttrs(manifest, preload, assetCrossOrigin),\n nonce,\n },\n })\n })\n })\n }\n\n const styles = matches\n .flatMap((match) => match.styles ?? [])\n .filter((style) => style !== undefined)\n .map(({ children, ...attrs }) => ({\n tag: 'style',\n attrs: {\n ...attrs,\n nonce,\n },\n children: children as string | undefined,\n })) satisfies Array<RouterManagedTag>\n\n const headScripts = matches\n .flatMap((match) => match.headScripts ?? [])\n .filter((script) => script !== undefined)\n .map(({ children, ...script }) => ({\n tag: 'script',\n attrs: {\n ...script,\n nonce,\n },\n children: children as string | undefined,\n })) satisfies Array<RouterManagedTag>\n\n const tags: Array<RouterManagedTag> = []\n appendUniqueUserTags(tags, resultMeta)\n tags.push(...preloadLinks)\n appendUniqueUserTags(tags, constructedLinks)\n tags.push(...manifestCssTags)\n appendUniqueUserTags(tags, styles)\n appendUniqueUserTags(tags, headScripts)\n return tags\n}\n\n/**\n * Build the head/link/meta/script tags from the renderable presented prefix.\n * Used internally by `HeadContent`.\n */\nexport const useTags = (assetCrossOrigin?: AssetCrossOriginConfig) => {\n const router = useRouter()\n const nonce = router.options.ssr?.nonce\n\n if (isServer ?? router.isServer) {\n return buildTagsFromMatches(\n router,\n nonce,\n router.stores.matches.get(),\n assetCrossOrigin,\n )\n }\n\n // eslint-disable-next-line react-hooks/rules-of-hooks -- condition is static\n const selectTags = React.useCallback(\n (matches: Array<AnyRouteMatch>) =>\n buildTagsFromMatches(router, nonce, matches, assetCrossOrigin),\n [assetCrossOrigin, nonce, router],\n )\n // eslint-disable-next-line react-hooks/rules-of-hooks -- condition is static\n return useStore(router.stores.matches, selectTags, deepEqual)\n}\n"],"mappings":"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"} |
| import { AssetCrossOriginConfig, RouterManagedTag } from '@tanstack/router-core'; | ||
| /** | ||
| * Build the list of head/link/meta/script tags to render for active matches. | ||
| * Build the head/link/meta/script tags from the renderable presented prefix. | ||
| * Used internally by `HeadContent`. | ||
| */ | ||
| export declare const useTags: (assetCrossOrigin?: AssetCrossOriginConfig) => RouterManagedTag[]; |
@@ -6,2 +6,3 @@ const require_runtime = require("./_virtual/_rolldown/runtime.cjs"); | ||
| react = require_runtime.__toESM(react, 1); | ||
| let _tanstack_router_core_isServer = require("@tanstack/router-core/isServer"); | ||
| //#region src/lazyRouteComponent.tsx | ||
@@ -21,27 +22,27 @@ /** | ||
| let error; | ||
| let reload; | ||
| const load = () => { | ||
| if (!loadPromise) loadPromise = importer().then((res) => { | ||
| loadPromise = void 0; | ||
| comp = res[exportName ?? "default"]; | ||
| }).catch((err) => { | ||
| error = err; | ||
| if ((0, _tanstack_router_core.isModuleNotFoundError)(error)) { | ||
| if (error instanceof Error && typeof window !== "undefined" && typeof sessionStorage !== "undefined") { | ||
| const storageKey = `tanstack_router_reload:${error.message}`; | ||
| if (!sessionStorage.getItem(storageKey)) { | ||
| sessionStorage.setItem(storageKey, "1"); | ||
| reload = true; | ||
| } | ||
| } | ||
| } | ||
| }); | ||
| if (!loadPromise) { | ||
| error = void 0; | ||
| loadPromise = importer().then((res) => { | ||
| if (!(_tanstack_router_core_isServer.isServer ?? typeof window === "undefined")) loadPromise = void 0; | ||
| comp = res[exportName ?? "default"]; | ||
| }).catch((err) => { | ||
| loadPromise = void 0; | ||
| error = err; | ||
| }); | ||
| } | ||
| return loadPromise; | ||
| }; | ||
| const lazyComp = function Lazy(props) { | ||
| if (reload) { | ||
| window.location.reload(); | ||
| throw new Promise(() => {}); | ||
| if (error) { | ||
| if ((0, _tanstack_router_core.isModuleNotFoundError)(error) && !(_tanstack_router_core_isServer.isServer ?? typeof window === "undefined") && typeof sessionStorage !== "undefined") { | ||
| const storageKey = `tanstack_router_reload:${error.message}`; | ||
| if (!sessionStorage.getItem(storageKey)) { | ||
| sessionStorage.setItem(storageKey, "1"); | ||
| window.location.reload(); | ||
| throw new Promise(() => {}); | ||
| } | ||
| } | ||
| throw error; | ||
| } | ||
| if (error) throw error; | ||
| if (!comp) if (require_utils.reactUse) require_utils.reactUse(load()); | ||
@@ -48,0 +49,0 @@ else throw load(); |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"lazyRouteComponent.cjs","names":[],"sources":["../../src/lazyRouteComponent.tsx"],"sourcesContent":["import * as React from 'react'\nimport { isModuleNotFoundError } from '@tanstack/router-core'\nimport { reactUse } from './utils'\nimport type { AsyncRouteComponent } from './route'\n\n/**\n * Wrap a dynamic import to create a route component that supports\n * `.preload()` and friendly reload-on-module-missing behavior.\n *\n * @param importer Function returning a module promise\n * @param exportName Named export to use (default: `default`)\n * @returns A lazy route component compatible with TanStack Router\n * @link https://tanstack.com/router/latest/docs/framework/react/api/router/lazyRouteComponentFunction\n */\nexport function lazyRouteComponent<\n T extends Record<string, any>,\n TKey extends keyof T = 'default',\n>(\n importer: () => Promise<T>,\n exportName?: TKey,\n): T[TKey] extends (props: infer TProps) => any\n ? AsyncRouteComponent<TProps>\n : never {\n let loadPromise: Promise<any> | undefined\n let comp: T[TKey] | T['default']\n let error: any\n let reload: boolean\n\n const load = () => {\n if (!loadPromise) {\n loadPromise = importer()\n .then((res) => {\n loadPromise = undefined\n comp = res[exportName ?? 'default']\n })\n .catch((err) => {\n // We don't want an error thrown from preload in this case, because\n // there's nothing we want to do about module not found during preload.\n // Record the error, the rest is handled during the render path.\n error = err\n // If the load fails due to module not found, it may mean a new version of\n // the build was deployed and the user's browser is still using an old version.\n // If this happens, the old version in the user's browser would have an outdated\n // URL to the lazy module.\n // In that case, we want to attempt one window refresh to get the latest.\n if (isModuleNotFoundError(error)) {\n if (\n error instanceof Error &&\n typeof window !== 'undefined' &&\n typeof sessionStorage !== 'undefined'\n ) {\n // Again, we want to reload one time on module not found error and not enter\n // a reload loop if there is some other issue besides an old deploy.\n // That's why we store our reload attempt in sessionStorage.\n // Use error.message as key because it contains the module path that failed.\n const storageKey = `tanstack_router_reload:${error.message}`\n if (!sessionStorage.getItem(storageKey)) {\n sessionStorage.setItem(storageKey, '1')\n reload = true\n }\n }\n }\n })\n }\n\n return loadPromise\n }\n\n const lazyComp = function Lazy(props: any) {\n // Now that we're out of preload and into actual render path,\n if (reload) {\n // If it was a module loading error,\n // throw eternal suspense while we wait for window to reload\n window.location.reload()\n throw new Promise(() => {})\n }\n if (error) {\n // Otherwise, just throw the error\n throw error\n }\n\n if (!comp) {\n if (reactUse) {\n reactUse(load())\n } else {\n throw load()\n }\n }\n\n return React.createElement(comp, props)\n }\n\n ;(lazyComp as any).preload = load\n\n return lazyComp as any\n}\n"],"mappings":";;;;;;;;;;;;;;;AAcA,SAAgB,mBAId,UACA,YAGQ;CACR,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CAEJ,MAAM,aAAa;EACjB,IAAI,CAAC,aACH,cAAc,SAAS,EACpB,MAAM,QAAQ;GACb,cAAc,KAAA;GACd,OAAO,IAAI,cAAc;EAC3B,CAAC,EACA,OAAO,QAAQ;GAId,QAAQ;GAMR,KAAA,GAAA,sBAAA,uBAA0B,KAAK;QAE3B,iBAAiB,SACjB,OAAO,WAAW,eAClB,OAAO,mBAAmB,aAC1B;KAKA,MAAM,aAAa,0BAA0B,MAAM;KACnD,IAAI,CAAC,eAAe,QAAQ,UAAU,GAAG;MACvC,eAAe,QAAQ,YAAY,GAAG;MACtC,SAAS;KACX;IACF;;EAEJ,CAAC;EAGL,OAAO;CACT;CAEA,MAAM,WAAW,SAAS,KAAK,OAAY;EAEzC,IAAI,QAAQ;GAGV,OAAO,SAAS,OAAO;GACvB,MAAM,IAAI,cAAc,CAAC,CAAC;EAC5B;EACA,IAAI,OAEF,MAAM;EAGR,IAAI,CAAC,MACH,IAAI,cAAA,UACF,cAAA,SAAS,KAAK,CAAC;OAEf,MAAM,KAAK;EAIf,OAAO,MAAM,cAAc,MAAM,KAAK;CACxC;CAEC,SAAkB,UAAU;CAE7B,OAAO;AACT"} | ||
| {"version":3,"file":"lazyRouteComponent.cjs","names":[],"sources":["../../src/lazyRouteComponent.tsx"],"sourcesContent":["import * as React from 'react'\nimport { isModuleNotFoundError } from '@tanstack/router-core'\nimport { isServer } from '@tanstack/router-core/isServer'\nimport { reactUse } from './utils'\nimport type { AsyncRouteComponent } from './route'\n\n/**\n * Wrap a dynamic import to create a route component that supports\n * `.preload()` and friendly reload-on-module-missing behavior.\n *\n * @param importer Function returning a module promise\n * @param exportName Named export to use (default: `default`)\n * @returns A lazy route component compatible with TanStack Router\n * @link https://tanstack.com/router/latest/docs/framework/react/api/router/lazyRouteComponentFunction\n */\nexport function lazyRouteComponent<\n T extends Record<string, any>,\n TKey extends keyof T = 'default',\n>(\n importer: () => Promise<T>,\n exportName?: TKey,\n): T[TKey] extends (props: infer TProps) => any\n ? AsyncRouteComponent<TProps>\n : never {\n let loadPromise: Promise<any> | undefined\n let comp: T[TKey] | T['default']\n let error: any\n\n const load = () => {\n if (!loadPromise) {\n error = undefined\n loadPromise = importer()\n .then((res) => {\n // Keep browser preload behavior unchanged; SSR can reuse the import.\n if (!(isServer ?? typeof window === 'undefined')) {\n loadPromise = undefined\n }\n comp = res[exportName ?? 'default']\n })\n .catch((err) => {\n loadPromise = undefined\n // We don't want an error thrown from preload in this case, because\n // there's nothing we want to do about module not found during preload.\n // Record the error, the rest is handled during the render path.\n error = err\n })\n }\n\n return loadPromise\n }\n\n const lazyComp = function Lazy(props: any) {\n if (error) {\n // A missing module can mean that a newer deployment replaced the URL.\n // Reload only for the error that is still current at render time, so a\n // successful retry cannot leave a stale reload request armed.\n if (\n isModuleNotFoundError(error) &&\n !(isServer ?? typeof window === 'undefined') &&\n typeof sessionStorage !== 'undefined'\n ) {\n const storageKey = `tanstack_router_reload:${error.message}`\n if (!sessionStorage.getItem(storageKey)) {\n sessionStorage.setItem(storageKey, '1')\n window.location.reload()\n // Suspend forever while the document reloads.\n throw new Promise(() => {})\n }\n }\n throw error\n }\n\n if (!comp) {\n if (reactUse) {\n reactUse(load())\n } else {\n throw load()\n }\n }\n\n return React.createElement(comp, props)\n }\n\n ;(lazyComp as any).preload = load\n\n return lazyComp as any\n}\n"],"mappings":";;;;;;;;;;;;;;;;AAeA,SAAgB,mBAId,UACA,YAGQ;CACR,IAAI;CACJ,IAAI;CACJ,IAAI;CAEJ,MAAM,aAAa;EACjB,IAAI,CAAC,aAAa;GAChB,QAAQ,KAAA;GACR,cAAc,SAAS,EACpB,MAAM,QAAQ;IAEb,IAAI,EAAE,+BAAA,YAAY,OAAO,WAAW,cAClC,cAAc,KAAA;IAEhB,OAAO,IAAI,cAAc;GAC3B,CAAC,EACA,OAAO,QAAQ;IACd,cAAc,KAAA;IAId,QAAQ;GACV,CAAC;EACL;EAEA,OAAO;CACT;CAEA,MAAM,WAAW,SAAS,KAAK,OAAY;EACzC,IAAI,OAAO;GAIT,KAAA,GAAA,sBAAA,uBACwB,KAAK,KAC3B,EAAE,+BAAA,YAAY,OAAO,WAAW,gBAChC,OAAO,mBAAmB,aAC1B;IACA,MAAM,aAAa,0BAA0B,MAAM;IACnD,IAAI,CAAC,eAAe,QAAQ,UAAU,GAAG;KACvC,eAAe,QAAQ,YAAY,GAAG;KACtC,OAAO,SAAS,OAAO;KAEvB,MAAM,IAAI,cAAc,CAAC,CAAC;IAC5B;GACF;GACA,MAAM;EACR;EAEA,IAAI,CAAC,MACH,IAAI,cAAA,UACF,cAAA,SAAS,KAAK,CAAC;OAEf,MAAM,KAAK;EAIf,OAAO,MAAM,cAAc,MAAM,KAAK;CACxC;CAEC,SAAkB,UAAU;CAE7B,OAAO;AACT"} |
@@ -9,5 +9,5 @@ "use client"; | ||
| react = require_runtime.__toESM(react, 1); | ||
| let _tanstack_router_core_isServer = require("@tanstack/router-core/isServer"); | ||
| let react_jsx_runtime = require("react/jsx-runtime"); | ||
| let _tanstack_react_store = require("@tanstack/react-store"); | ||
| let _tanstack_router_core_isServer = require("@tanstack/router-core/isServer"); | ||
| let react_dom = require("react-dom"); | ||
@@ -14,0 +14,0 @@ //#region src/link.tsx |
+53
-192
| "use client"; | ||
| const require_runtime = require("./_virtual/_rolldown/runtime.cjs"); | ||
| const require_utils = require("./utils.cjs"); | ||
| const require_CatchBoundary = require("./CatchBoundary.cjs"); | ||
@@ -15,82 +14,45 @@ const require_ClientOnly = require("./ClientOnly.cjs"); | ||
| react = require_runtime.__toESM(react, 1); | ||
| let _tanstack_router_core_isServer = require("@tanstack/router-core/isServer"); | ||
| let react_jsx_runtime = require("react/jsx-runtime"); | ||
| let _tanstack_react_store = require("@tanstack/react-store"); | ||
| let _tanstack_router_core_isServer = require("@tanstack/router-core/isServer"); | ||
| //#region src/Match.tsx | ||
| var matchViewFieldsEqual = (a, b) => a.routeId === b.routeId && a._displayPending === b._displayPending; | ||
| function renderPending(router, route) { | ||
| const PendingComponent = route?.options.pendingComponent ?? router.options.defaultPendingComponent; | ||
| return PendingComponent ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(PendingComponent, {}) : null; | ||
| } | ||
| var outletMatchSelectionEqual = (a, b) => a[0] === b[0] && a[1] === b[1]; | ||
| var Match = react.memo(function MatchImpl({ matchId }) { | ||
| var Match = react.memo(function MatchImpl({ routeId }) { | ||
| const router = require_useRouter.useRouter(); | ||
| if (_tanstack_router_core_isServer.isServer ?? router.isServer) { | ||
| const match = router.stores.matchStores.get(matchId)?.get(); | ||
| if (!match) { | ||
| if (process.env.NODE_ENV !== "production") throw new Error(`Invariant failed: Could not find match for matchId "${matchId}". Please file an issue!`); | ||
| (0, _tanstack_router_core.invariant)(); | ||
| } | ||
| const routeId = match.routeId; | ||
| const parentRouteId = router.routesById[routeId].parentRoute?.id; | ||
| return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(MatchView, { | ||
| router, | ||
| matchId, | ||
| resetKey: router.stores.loadedAt.get(), | ||
| matchState: { | ||
| routeId, | ||
| ssr: match.ssr, | ||
| _displayPending: match._displayPending, | ||
| parentRouteId | ||
| } | ||
| }); | ||
| } | ||
| const matchStore = router.stores.matchStores.get(matchId); | ||
| if (!matchStore) { | ||
| if (process.env.NODE_ENV !== "production") throw new Error(`Invariant failed: Could not find match for matchId "${matchId}". Please file an issue!`); | ||
| (0, _tanstack_router_core.invariant)(); | ||
| } | ||
| const resetKey = (0, _tanstack_react_store.useStore)(router.stores.loadedAt, (loadedAt) => loadedAt); | ||
| const match = (0, _tanstack_react_store.useStore)(matchStore, (value) => value, matchViewFieldsEqual); | ||
| if (_tanstack_router_core_isServer.isServer ?? router.isServer) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(MatchView, { | ||
| router, | ||
| match: router.stores.byRoute.get(routeId).get() | ||
| }); | ||
| return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(MatchView, { | ||
| router, | ||
| matchId, | ||
| resetKey, | ||
| matchState: react.useMemo(() => { | ||
| const routeId = match.routeId; | ||
| const parentRouteId = router.routesById[routeId].parentRoute?.id; | ||
| return { | ||
| routeId, | ||
| ssr: match.ssr, | ||
| _displayPending: match._displayPending, | ||
| parentRouteId | ||
| }; | ||
| }, [ | ||
| match._displayPending, | ||
| match.routeId, | ||
| match.ssr, | ||
| router.routesById | ||
| ]) | ||
| match: (0, _tanstack_react_store.useStore)(router.stores.getMatchStore(routeId), (value) => value) | ||
| }); | ||
| }); | ||
| function MatchView({ router, matchId, resetKey, matchState }) { | ||
| const route = router.routesById[matchState.routeId]; | ||
| const PendingComponent = route.options.pendingComponent ?? router.options.defaultPendingComponent; | ||
| const pendingElement = PendingComponent ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(PendingComponent, {}) : null; | ||
| function MatchView({ router, match }) { | ||
| const route = router.routesById[match.routeId]; | ||
| const pendingElement = renderPending(router, route); | ||
| const routeErrorComponent = route.options.errorComponent ?? router.options.defaultErrorComponent; | ||
| const routeOnCatch = route.options.onCatch ?? router.options.defaultOnCatch; | ||
| const routeNotFoundComponent = route.isRoot ? route.options.notFoundComponent ?? router.options.notFoundRoute?.options.component : route.options.notFoundComponent; | ||
| const resolvedNoSsr = matchState.ssr === false || matchState.ssr === "data-only"; | ||
| const ResolvedSuspenseBoundary = (!route.isRoot || route.options.wrapInSuspense || resolvedNoSsr) && (route.options.wrapInSuspense ?? PendingComponent ?? (route.options.errorComponent?.preload || resolvedNoSsr)) ? react.Suspense : require_SafeFragment.SafeFragment; | ||
| const resolvedNoSsr = match.ssr === false || match.ssr === "data-only"; | ||
| const ResolvedSuspenseBoundary = route.options.wrapInSuspense ?? pendingElement ?? (route.options.errorComponent?.preload || resolvedNoSsr) ? react.Suspense : require_SafeFragment.SafeFragment; | ||
| const ResolvedCatchBoundary = routeErrorComponent ? require_CatchBoundary.CatchBoundary : require_SafeFragment.SafeFragment; | ||
| const ResolvedNotFoundBoundary = routeNotFoundComponent ? require_not_found.CatchNotFound : require_SafeFragment.SafeFragment; | ||
| return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(route.isRoot ? route.options.shellComponent ?? require_SafeFragment.SafeFragment : require_SafeFragment.SafeFragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_matchContext.matchContext.Provider, { | ||
| value: matchId, | ||
| value: match.routeId, | ||
| children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ResolvedSuspenseBoundary, { | ||
| fallback: pendingElement, | ||
| children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ResolvedCatchBoundary, { | ||
| getResetKey: () => resetKey, | ||
| errorComponent: routeErrorComponent || require_CatchBoundary.ErrorComponent, | ||
| getResetKey: () => match, | ||
| errorComponent: routeErrorComponent, | ||
| onCatch: (error, errorInfo) => { | ||
| if ((0, _tanstack_router_core.isNotFound)(error)) { | ||
| error.routeId ??= matchState.routeId; | ||
| error.routeId ??= match.routeId; | ||
| throw error; | ||
| } | ||
| if (process.env.NODE_ENV !== "production") console.warn(`Warning: Error in route match: ${matchId}`); | ||
| if (process.env.NODE_ENV !== "production") console.warn(`Warning: Error in route match: ${match.id}`); | ||
| routeOnCatch?.(error, errorInfo); | ||
@@ -100,86 +62,21 @@ }, | ||
| fallback: (error) => { | ||
| error.routeId ??= matchState.routeId; | ||
| if (!routeNotFoundComponent || error.routeId && error.routeId !== matchState.routeId || !error.routeId && !route.isRoot) throw error; | ||
| error.routeId ??= match.routeId; | ||
| if (error.routeId !== match.routeId) throw error; | ||
| return react.createElement(routeNotFoundComponent, error); | ||
| }, | ||
| children: resolvedNoSsr || matchState._displayPending ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_ClientOnly.ClientOnly, { | ||
| children: resolvedNoSsr ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_ClientOnly.ClientOnly, { | ||
| fallback: pendingElement, | ||
| children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(MatchInner, { matchId }) | ||
| }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(MatchInner, { matchId }) | ||
| children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(MatchInner, { match }) | ||
| }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(MatchInner, { match }) | ||
| }) | ||
| }) | ||
| }) | ||
| }), 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] }); | ||
| }), (_tanstack_router_core_isServer.isServer ?? router.isServer) && route.parentRoute?.id === _tanstack_router_core.rootRouteId && router.options.scrollRestoration ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_scroll_restoration.ScrollRestoration, {}) : null] }); | ||
| } | ||
| function OnRendered() { | ||
| var MatchInner = react.memo(function MatchInnerImpl({ match }) { | ||
| const router = require_useRouter.useRouter(); | ||
| if (_tanstack_router_core_isServer.isServer ?? router.isServer) return null; | ||
| const prevResolvedLocationRef = react.useRef(); | ||
| require_utils.useLayoutEffect(() => { | ||
| 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; | ||
| } | ||
| var MatchInner = react.memo(function MatchInnerImpl({ matchId }) { | ||
| const router = require_useRouter.useRouter(); | ||
| const getMatchPromise = (match, key) => { | ||
| return router.getMatch(match.id)?._nonReactive[key] ?? match._nonReactive[key]; | ||
| }; | ||
| if (_tanstack_router_core_isServer.isServer ?? router.isServer) { | ||
| const match = router.stores.matchStores.get(matchId)?.get(); | ||
| if (!match) { | ||
| if (process.env.NODE_ENV !== "production") throw new Error(`Invariant failed: Could not find match for matchId "${matchId}". Please file an issue!`); | ||
| (0, _tanstack_router_core.invariant)(); | ||
| } | ||
| const routeId = match.routeId; | ||
| const route = router.routesById[routeId]; | ||
| const remountDeps = (router.routesById[routeId].options.remountDeps ?? router.options.defaultRemountDeps)?.({ | ||
| routeId, | ||
| loaderDeps: match.loaderDeps, | ||
| params: match._strictParams, | ||
| search: match._strictSearch | ||
| }); | ||
| const key = remountDeps ? JSON.stringify(remountDeps) : void 0; | ||
| const Comp = route.options.component ?? router.options.defaultComponent; | ||
| const out = Comp ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Comp, {}, key) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Outlet, {}); | ||
| if (match._displayPending) throw getMatchPromise(match, "displayPendingPromise"); | ||
| if (match._forcePending) throw getMatchPromise(match, "minPendingPromise"); | ||
| if (match.status === "pending") throw getMatchPromise(match, "loadPromise"); | ||
| if (match.status === "notFound") { | ||
| if (!(0, _tanstack_router_core.isNotFound)(match.error)) { | ||
| if (process.env.NODE_ENV !== "production") throw new Error("Invariant failed: Expected a notFound error"); | ||
| (0, _tanstack_router_core.invariant)(); | ||
| } | ||
| return require_renderRouteNotFound.renderRouteNotFound(router, route, match.error); | ||
| } | ||
| if (match.status === "redirected") { | ||
| if (!(0, _tanstack_router_core.isRedirect)(match.error)) { | ||
| if (process.env.NODE_ENV !== "production") throw new Error("Invariant failed: Expected a redirect error"); | ||
| (0, _tanstack_router_core.invariant)(); | ||
| } | ||
| throw getMatchPromise(match, "loadPromise"); | ||
| } | ||
| if (match.status === "error") return /* @__PURE__ */ (0, react_jsx_runtime.jsx)((route.options.errorComponent ?? router.options.defaultErrorComponent) || require_CatchBoundary.ErrorComponent, { | ||
| error: match.error, | ||
| reset: void 0, | ||
| info: { componentStack: "" } | ||
| }); | ||
| return out; | ||
| } | ||
| const matchStore = router.stores.matchStores.get(matchId); | ||
| if (!matchStore) { | ||
| if (process.env.NODE_ENV !== "production") throw new Error(`Invariant failed: Could not find match for matchId "${matchId}". Please file an issue!`); | ||
| (0, _tanstack_router_core.invariant)(); | ||
| } | ||
| const match = (0, _tanstack_react_store.useStore)(matchStore, (value) => value); | ||
| const routeId = match.routeId; | ||
| const route = router.routesById[routeId]; | ||
| const key = react.useMemo(() => { | ||
| const remountDeps = (router.routesById[routeId].options.remountDeps ?? router.options.defaultRemountDeps)?.({ | ||
| const remountDeps = (route.options.remountDeps ?? router.options.defaultRemountDeps)?.({ | ||
| routeId, | ||
@@ -196,9 +93,8 @@ loaderDeps: match.loaderDeps, | ||
| match._strictSearch, | ||
| router.options.defaultRemountDeps, | ||
| router.routesById | ||
| route.options.remountDeps, | ||
| router.options.defaultRemountDeps | ||
| ]); | ||
| const out = react.useMemo(() => { | ||
| const Comp = route.options.component ?? router.options.defaultComponent; | ||
| if (Comp) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Comp, {}, key); | ||
| return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Outlet, {}); | ||
| return Comp ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Comp, {}, key) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Outlet, {}); | ||
| }, [ | ||
@@ -209,35 +105,7 @@ key, | ||
| ]); | ||
| if (match._displayPending) throw getMatchPromise(match, "displayPendingPromise"); | ||
| if (match._forcePending) throw getMatchPromise(match, "minPendingPromise"); | ||
| if (match.status === "pending") { | ||
| const pendingMinMs = route.options.pendingMinMs ?? router.options.defaultPendingMinMs; | ||
| if (pendingMinMs) { | ||
| const routerMatch = router.getMatch(match.id); | ||
| if (routerMatch && !routerMatch._nonReactive.minPendingPromise) { | ||
| if (!(_tanstack_router_core_isServer.isServer ?? router.isServer)) { | ||
| const minPendingPromise = (0, _tanstack_router_core.createControlledPromise)(); | ||
| routerMatch._nonReactive.minPendingPromise = minPendingPromise; | ||
| setTimeout(() => { | ||
| minPendingPromise.resolve(); | ||
| routerMatch._nonReactive.minPendingPromise = void 0; | ||
| }, pendingMinMs); | ||
| } | ||
| } | ||
| } | ||
| throw getMatchPromise(match, "loadPromise"); | ||
| if (router._tx) throw router._tx[5]; | ||
| return renderPending(router, route); | ||
| } | ||
| if (match.status === "notFound") { | ||
| if (!(0, _tanstack_router_core.isNotFound)(match.error)) { | ||
| if (process.env.NODE_ENV !== "production") throw new Error("Invariant failed: Expected a notFound error"); | ||
| (0, _tanstack_router_core.invariant)(); | ||
| } | ||
| return require_renderRouteNotFound.renderRouteNotFound(router, route, match.error); | ||
| } | ||
| if (match.status === "redirected") { | ||
| if (!(0, _tanstack_router_core.isRedirect)(match.error)) { | ||
| if (process.env.NODE_ENV !== "production") throw new Error("Invariant failed: Expected a redirect error"); | ||
| (0, _tanstack_router_core.invariant)(); | ||
| } | ||
| throw getMatchPromise(match, "loadPromise"); | ||
| } | ||
| if (match.status === "notFound") return require_renderRouteNotFound.renderRouteNotFound(router, route, match.error); | ||
| if (match.status === "error") { | ||
@@ -261,33 +129,25 @@ if (_tanstack_router_core_isServer.isServer ?? router.isServer) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)((route.options.errorComponent ?? router.options.defaultErrorComponent) || require_CatchBoundary.ErrorComponent, { | ||
| const router = require_useRouter.useRouter(); | ||
| const matchId = react.useContext(require_matchContext.matchContext); | ||
| let routeId; | ||
| let parentGlobalNotFound = false; | ||
| let childMatchId; | ||
| const routeId = react.useContext(require_matchContext.matchContext); | ||
| let parentGlobalNotFound; | ||
| let parentNotFoundError; | ||
| let childRouteId; | ||
| if (_tanstack_router_core_isServer.isServer ?? router.isServer) { | ||
| const matches = router.stores.matches.get(); | ||
| const parentIndex = matchId ? matches.findIndex((match) => match.id === matchId) : -1; | ||
| const parentMatch = parentIndex >= 0 ? matches[parentIndex] : void 0; | ||
| routeId = parentMatch?.routeId; | ||
| parentGlobalNotFound = parentMatch?.globalNotFound ?? false; | ||
| childMatchId = parentIndex >= 0 ? matches[parentIndex + 1]?.id : void 0; | ||
| const parentIndex = matches.findIndex((match) => match.routeId === routeId); | ||
| const parentMatch = matches[parentIndex]; | ||
| parentGlobalNotFound = !!parentMatch._notFound; | ||
| parentNotFoundError = parentMatch.error; | ||
| childRouteId = matches[parentIndex + 1]?.routeId; | ||
| } else { | ||
| const parentMatchStore = matchId ? router.stores.matchStores.get(matchId) : void 0; | ||
| [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) => { | ||
| return ids[ids.findIndex((id) => id === matchId) + 1]; | ||
| const parentMatchStore = router.stores.getMatchStore(routeId); | ||
| [parentGlobalNotFound, parentNotFoundError] = (0, _tanstack_react_store.useStore)(parentMatchStore, (match) => [!!match._notFound, match.error], outletMatchSelectionEqual); | ||
| childRouteId = (0, _tanstack_react_store.useStore)(router.stores.ids, (ids) => { | ||
| return ids[ids.indexOf(routeId) + 1]; | ||
| }); | ||
| } | ||
| const route = routeId ? router.routesById[routeId] : void 0; | ||
| const pendingElement = router.options.defaultPendingComponent ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(router.options.defaultPendingComponent, {}) : null; | ||
| if (parentGlobalNotFound) { | ||
| if (!route) { | ||
| if (process.env.NODE_ENV !== "production") throw new Error("Invariant failed: Could not resolve route for Outlet render"); | ||
| (0, _tanstack_router_core.invariant)(); | ||
| } | ||
| return require_renderRouteNotFound.renderRouteNotFound(router, route, void 0); | ||
| } | ||
| if (!childMatchId) return null; | ||
| const nextMatch = /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Match, { matchId: childMatchId }); | ||
| if (parentGlobalNotFound) return require_renderRouteNotFound.renderRouteNotFound(router, router.routesById[routeId], parentNotFoundError); | ||
| if (!childRouteId) return null; | ||
| const nextMatch = /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Match, { routeId: childRouteId }); | ||
| if (routeId === _tanstack_router_core.rootRouteId) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react.Suspense, { | ||
| fallback: pendingElement, | ||
| fallback: renderPending(router), | ||
| children: nextMatch | ||
@@ -300,3 +160,4 @@ }); | ||
| exports.Outlet = Outlet; | ||
| exports.renderPending = renderPending; | ||
| //# sourceMappingURL=Match.cjs.map |
@@ -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 {\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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"} | ||
| {"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 { isNotFound, rootRouteId } 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 type {\n AnyRoute,\n AnyRouteMatch,\n RootRouteOptions,\n} from '@tanstack/router-core'\n\nexport function renderPending(\n router: ReturnType<typeof useRouter>,\n route?: AnyRoute,\n) {\n const PendingComponent =\n route?.options.pendingComponent ?? router.options.defaultPendingComponent\n return PendingComponent ? <PendingComponent /> : null\n}\n\ntype OutletMatchSelection = [\n parentGlobalNotFound: boolean,\n parentNotFoundError: unknown,\n]\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 routeId,\n}: {\n routeId: string\n}) {\n const router = useRouter()\n\n if (isServer ?? router.isServer) {\n const match = router.stores.byRoute.get(routeId)!.get()!\n return <MatchView router={router} match={match} />\n }\n\n const matchStore = router.stores.getMatchStore(routeId)\n // eslint-disable-next-line react-hooks/rules-of-hooks\n const match = useStore(matchStore, (value) => value)\n return <MatchView router={router} match={match!} />\n})\n\nfunction MatchView({\n router,\n match,\n}: {\n router: ReturnType<typeof useRouter>\n match: AnyRouteMatch\n}) {\n const route: AnyRoute = router.routesById[match.routeId]\n\n const pendingElement = renderPending(router, route)\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 _notFound 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 = match.ssr === false || match.ssr === 'data-only'\n const ResolvedSuspenseBoundary =\n (route.options.wrapInSuspense ??\n pendingElement ??\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={match.routeId}>\n <ResolvedSuspenseBoundary fallback={pendingElement}>\n <ResolvedCatchBoundary\n getResetKey={() => match}\n errorComponent={routeErrorComponent as any}\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 ??= match.routeId\n throw error\n }\n if (process.env.NODE_ENV !== 'production') {\n console.warn(`Warning: Error in route match: ${match.id}`)\n }\n routeOnCatch?.(error, errorInfo)\n }}\n >\n <ResolvedNotFoundBoundary\n fallback={(error) => {\n error.routeId ??= match.routeId\n\n if (error.routeId !== match.routeId) {\n throw error\n }\n\n return React.createElement(\n routeNotFoundComponent!,\n error as any,\n )\n }}\n >\n {resolvedNoSsr ? (\n <ClientOnly fallback={pendingElement}>\n <MatchInner match={match} />\n </ClientOnly>\n ) : (\n <MatchInner match={match} />\n )}\n </ResolvedNotFoundBoundary>\n </ResolvedCatchBoundary>\n </ResolvedSuspenseBoundary>\n </matchContext.Provider>\n {(isServer ?? router.isServer) &&\n route.parentRoute?.id === rootRouteId &&\n router.options.scrollRestoration ? (\n <ScrollRestoration />\n ) : null}\n </ShellComponent>\n )\n}\n\nexport const MatchInner = React.memo(function MatchInnerImpl({\n match,\n}: {\n match: AnyRouteMatch\n}): any {\n const router = useRouter()\n const routeId = match.routeId\n const route = router.routesById[routeId] as AnyRoute\n const key = React.useMemo(() => {\n const remountFn =\n route.options.remountDeps ?? 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 route.options.remountDeps,\n router.options.defaultRemountDeps,\n ])\n const out = React.useMemo(() => {\n const Comp = route.options.component ?? router.options.defaultComponent\n return Comp ? <Comp key={key} /> : <Outlet />\n }, [key, route.options.component, router.options.defaultComponent])\n\n if (match.status === 'pending') {\n if (router._tx) {\n throw router._tx[5]\n }\n return renderPending(router, route)\n }\n\n if (match.status === 'notFound') {\n return renderRouteNotFound(router, route, match.error)\n }\n\n if (match.status === 'error') {\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 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 routeId = React.useContext(matchContext)!\n\n let parentGlobalNotFound: boolean\n let parentNotFoundError: unknown\n let childRouteId: string | undefined\n\n if (isServer ?? router.isServer) {\n const matches = router.stores.matches.get()\n const parentIndex = matches.findIndex((match) => match.routeId === routeId)\n const parentMatch = matches[parentIndex]!\n parentGlobalNotFound = !!parentMatch._notFound\n parentNotFoundError = parentMatch.error\n childRouteId = matches[parentIndex + 1]?.routeId\n } else {\n const parentMatchStore = router.stores.getMatchStore(routeId)\n\n // eslint-disable-next-line react-hooks/rules-of-hooks\n ;[parentGlobalNotFound, parentNotFoundError] = useStore(\n parentMatchStore,\n (match): OutletMatchSelection => [!!match!._notFound, match!.error],\n outletMatchSelectionEqual,\n )\n\n // eslint-disable-next-line react-hooks/rules-of-hooks\n childRouteId = useStore(router.stores.ids, (ids) => {\n return ids[ids.indexOf(routeId) + 1]\n })\n }\n\n if (parentGlobalNotFound) {\n return renderRouteNotFound(\n router,\n router.routesById[routeId],\n parentNotFoundError,\n )\n }\n\n if (!childRouteId) {\n return null\n }\n\n const nextMatch = <Match routeId={childRouteId} />\n\n if (routeId === rootRouteId) {\n return (\n <React.Suspense fallback={renderPending(router)}>\n {nextMatch}\n </React.Suspense>\n )\n }\n\n return nextMatch\n})\n"],"mappings":"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"} |
@@ -0,7 +1,10 @@ | ||
| import { useRouter } from './useRouter.cjs'; | ||
| import { AnyRoute, AnyRouteMatch } from '@tanstack/router-core'; | ||
| import * as React from 'react'; | ||
| export declare const Match: React.MemoExoticComponent<({ matchId, }: { | ||
| matchId: string; | ||
| export declare function renderPending(router: ReturnType<typeof useRouter>, route?: AnyRoute): import("react/jsx-runtime").JSX.Element | null; | ||
| export declare const Match: React.MemoExoticComponent<({ routeId, }: { | ||
| routeId: string; | ||
| }) => import("react/jsx-runtime").JSX.Element>; | ||
| export declare const MatchInner: React.MemoExoticComponent<({ matchId, }: { | ||
| matchId: string; | ||
| export declare const MatchInner: React.MemoExoticComponent<({ match, }: { | ||
| match: AnyRouteMatch; | ||
| }) => any>; | ||
@@ -8,0 +11,0 @@ /** |
+30
-33
| "use client"; | ||
| const require_runtime = require("./_virtual/_rolldown/runtime.cjs"); | ||
| const require_utils = require("./utils.cjs"); | ||
| const require_CatchBoundary = require("./CatchBoundary.cjs"); | ||
@@ -13,5 +14,5 @@ const require_matchContext = require("./matchContext.cjs"); | ||
| react = require_runtime.__toESM(react, 1); | ||
| let _tanstack_router_core_isServer = require("@tanstack/router-core/isServer"); | ||
| let react_jsx_runtime = require("react/jsx-runtime"); | ||
| let _tanstack_react_store = require("@tanstack/react-store"); | ||
| let _tanstack_router_core_isServer = require("@tanstack/router-core/isServer"); | ||
| //#region src/Matches.tsx | ||
@@ -24,8 +25,9 @@ /** | ||
| const router = require_useRouter.useRouter(); | ||
| const PendingComponent = router.routesById[_tanstack_router_core.rootRouteId].options.pendingComponent ?? router.options.defaultPendingComponent; | ||
| const pendingElement = PendingComponent ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(PendingComponent, {}) : null; | ||
| const inner = /* @__PURE__ */ (0, react_jsx_runtime.jsxs)((_tanstack_router_core_isServer.isServer ?? router.isServer) || typeof document !== "undefined" && router.ssr ? require_SafeFragment.SafeFragment : react.Suspense, { | ||
| const rootRoute = router.routesById[_tanstack_router_core.rootRouteId]; | ||
| const pendingElement = require_Match.renderPending(router, rootRoute); | ||
| const ResolvedSuspense = (_tanstack_router_core_isServer.isServer ?? router.isServer) || router.ssr ? require_SafeFragment.SafeFragment : react.Suspense; | ||
| const inner = /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [!(_tanstack_router_core_isServer.isServer ?? router.isServer) && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_Transitioner.Transitioner, {}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ResolvedSuspense, { | ||
| fallback: pendingElement, | ||
| children: [!(_tanstack_router_core_isServer.isServer ?? router.isServer) && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_Transitioner.Transitioner, {}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(MatchesInner, {})] | ||
| }); | ||
| children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(MatchesInner, {}) | ||
| })] }); | ||
| return router.options.InnerWrap ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(router.options.InnerWrap, { children: inner }) : inner; | ||
@@ -35,11 +37,13 @@ } | ||
| const router = require_useRouter.useRouter(); | ||
| const _isServer = _tanstack_router_core_isServer.isServer ?? router.isServer; | ||
| const matchId = _isServer ? router.stores.firstId.get() : (0, _tanstack_react_store.useStore)(router.stores.firstId, (id) => id); | ||
| const resetKey = _isServer ? router.stores.loadedAt.get() : (0, _tanstack_react_store.useStore)(router.stores.loadedAt, (loadedAt) => loadedAt); | ||
| const matchComponent = matchId ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_Match.Match, { matchId }) : null; | ||
| const matches = _tanstack_router_core_isServer.isServer ?? router.isServer ? router.stores.matches.get() : (0, _tanstack_react_store.useStore)(router.stores.matches, (value) => value); | ||
| const match = matches[0]; | ||
| const routeId = match?.routeId; | ||
| require_utils.useLayoutEffect(() => { | ||
| router._rendered(matches); | ||
| }, [matches, router]); | ||
| const matchComponent = routeId ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_Match.Match, { routeId }) : null; | ||
| return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_matchContext.matchContext.Provider, { | ||
| value: matchId, | ||
| value: routeId, | ||
| children: router.options.disableGlobalCatchBoundary ? matchComponent : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_CatchBoundary.CatchBoundary, { | ||
| getResetKey: () => resetKey, | ||
| errorComponent: require_CatchBoundary.ErrorComponent, | ||
| getResetKey: () => match, | ||
| onCatch: process.env.NODE_ENV !== "production" ? (error) => { | ||
@@ -67,3 +71,7 @@ console.warn(`Warning: The following error wasn't caught by any route! At the very least, consider setting an 'errorComponent' in your RootRoute!`); | ||
| const router = require_useRouter.useRouter(); | ||
| if (!(_tanstack_router_core_isServer.isServer ?? router.isServer)) (0, _tanstack_react_store.useStore)(router.stores.matchRouteDeps, (d) => d); | ||
| if (!(_tanstack_router_core_isServer.isServer ?? router.isServer)) { | ||
| (0, _tanstack_react_store.useStore)(router.stores.location, (location) => location.href); | ||
| (0, _tanstack_react_store.useStore)(router.stores.resolvedLocation, (location) => location?.href); | ||
| (0, _tanstack_react_store.useStore)(router.stores.status, (status) => status); | ||
| } | ||
| return react.useCallback((opts) => { | ||
@@ -100,21 +108,10 @@ const { pending, caseSensitive, fuzzy, includeSearch, ...rest } = opts; | ||
| /** | ||
| * Read the full array of active route matches or select a derived subset. | ||
| * | ||
| * Useful for debugging, breadcrumbs, or aggregating metadata across matches. | ||
| * | ||
| * @returns The array of matches (or the selected value). | ||
| * @link https://tanstack.com/router/latest/docs/framework/react/api/router/useMatchesHook | ||
| * Read the presented route matches above the current match, or select a | ||
| * derived value from them. | ||
| */ | ||
| /** | ||
| * Read the full array of active route matches or select a derived subset. | ||
| * | ||
| * Useful for debugging, breadcrumbs, or aggregating metadata across matches. | ||
| * | ||
| * @link https://tanstack.com/router/latest/docs/framework/react/api/router/useMatchesHook | ||
| */ | ||
| function useParentMatches(opts) { | ||
| const contextMatchId = react.useContext(require_matchContext.matchContext); | ||
| const contextRouteId = react.useContext(require_matchContext.matchContext); | ||
| return useMatches({ | ||
| select: (matches) => { | ||
| matches = matches.slice(0, matches.findIndex((d) => d.id === contextMatchId)); | ||
| matches = matches.slice(0, matches.findIndex((d) => d.routeId === contextRouteId)); | ||
| return opts?.select ? opts.select(matches) : matches; | ||
@@ -126,10 +123,10 @@ }, | ||
| /** | ||
| * Read the array of active route matches that are children of the current | ||
| * match (or selected parent) in the match tree. | ||
| * Read the presented route matches below the current match, or select a | ||
| * derived value from them. | ||
| */ | ||
| function useChildMatches(opts) { | ||
| const contextMatchId = react.useContext(require_matchContext.matchContext); | ||
| const contextRouteId = react.useContext(require_matchContext.matchContext); | ||
| return useMatches({ | ||
| select: (matches) => { | ||
| matches = matches.slice(matches.findIndex((d) => d.id === contextMatchId) + 1); | ||
| matches = matches.slice(matches.findIndex((d) => d.routeId === contextRouteId) + 1); | ||
| return opts?.select ? opts.select(matches) : matches; | ||
@@ -136,0 +133,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 { 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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"} | ||
| {"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 } from './CatchBoundary'\nimport { useRouter } from './useRouter'\nimport { useStructuralSharing } from './useMatch'\nimport { useLayoutEffect } from './utils'\nimport { Transitioner } from './Transitioner'\nimport { matchContext } from './matchContext'\nimport { Match, renderPending } 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 pendingElement = renderPending(router, rootRoute)\n\n // Do not render a root Suspense during SSR or hydrating from SSR\n const ResolvedSuspense =\n (isServer ?? router.isServer) || router.ssr ? SafeFragment : React.Suspense\n\n const inner = (\n <>\n {!(isServer ?? router.isServer) && <Transitioner />}\n <ResolvedSuspense fallback={pendingElement}>\n <MatchesInner />\n </ResolvedSuspense>\n </>\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 matches =\n (isServer ?? router.isServer)\n ? router.stores.matches.get()\n : // eslint-disable-next-line react-hooks/rules-of-hooks\n useStore(router.stores.matches, (value) => value)\n const match = matches[0]\n const routeId = match?.routeId\n\n useLayoutEffect(() => {\n router._rendered!(matches)\n }, [matches, router])\n\n const matchComponent = routeId ? <Match routeId={routeId} /> : null\n\n return (\n <matchContext.Provider value={routeId}>\n {router.options.disableGlobalCatchBoundary ? (\n matchComponent\n ) : (\n <CatchBoundary\n getResetKey={() => match}\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.location, (location) => location.href)\n // eslint-disable-next-line react-hooks/rules-of-hooks\n useStore(router.stores.resolvedLocation, (location) => location?.href)\n // eslint-disable-next-line react-hooks/rules-of-hooks\n useStore(router.stores.status, (status) => status)\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 presented route matches above the current match, or select a\n * derived value from them.\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 contextRouteId = React.useContext(matchContext)\n\n return useMatches({\n select: (matches: Array<MakeRouteMatchUnion<TRouter>>) => {\n matches = matches.slice(\n 0,\n matches.findIndex((d) => d.routeId === contextRouteId),\n )\n return opts?.select ? opts.select(matches) : matches\n },\n structuralSharing: opts?.structuralSharing,\n } as any)\n}\n\n/**\n * Read the presented route matches below the current match, or select a\n * derived value from them.\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 contextRouteId = React.useContext(matchContext)\n\n return useMatches({\n select: (matches: Array<MakeRouteMatchUnion<TRouter>>) => {\n matches = matches.slice(\n matches.findIndex((d) => d.routeId === contextRouteId) + 1,\n )\n return opts?.select ? opts.select(matches) : matches\n },\n structuralSharing: opts?.structuralSharing,\n } as any)\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AA+CA,SAAgB,UAAU;CACxB,MAAM,SAAS,kBAAA,UAAU;CACzB,MAAM,YAAsB,OAAO,WAAW,sBAAA;CAE9C,MAAM,iBAAiB,cAAA,cAAc,QAAQ,SAAS;CAGtD,MAAM,oBACH,+BAAA,YAAY,OAAO,aAAa,OAAO,MAAM,qBAAA,eAAe,MAAM;CAErE,MAAM,QACJ,iBAAA,GAAA,kBAAA,MAAA,kBAAA,UAAA,EAAA,UAAA,CACG,EAAE,+BAAA,YAAY,OAAO,aAAa,iBAAA,GAAA,kBAAA,KAAC,qBAAA,cAAD,CAAe,CAAA,GAClD,iBAAA,GAAA,kBAAA,KAAC,kBAAD;EAAkB,UAAU;YAC1B,iBAAA,GAAA,kBAAA,KAAC,cAAD,CAAe,CAAA;CACC,CAAA,CAClB,EAAA,CAAA;CAGJ,OAAO,OAAO,QAAQ,YACpB,iBAAA,GAAA,kBAAA,KAAC,OAAO,QAAQ,WAAhB,EAAA,UAA2B,MAAgC,CAAA,IAE3D;AAEJ;AAEA,SAAS,eAAe;CACtB,MAAM,SAAS,kBAAA,UAAU;CACzB,MAAM,UACH,+BAAA,YAAY,OAAO,WAChB,OAAO,OAAO,QAAQ,IAAI,KAAA,GAAA,sBAAA,UAEjB,OAAO,OAAO,UAAU,UAAU,KAAK;CACtD,MAAM,QAAQ,QAAQ;CACtB,MAAM,UAAU,OAAO;CAEvB,cAAA,sBAAsB;EACpB,OAAO,UAAW,OAAO;CAC3B,GAAG,CAAC,SAAS,MAAM,CAAC;CAEpB,MAAM,iBAAiB,UAAU,iBAAA,GAAA,kBAAA,KAAC,cAAA,OAAD,EAAgB,QAAU,CAAA,IAAI;CAE/D,OACE,iBAAA,GAAA,kBAAA,KAAC,qBAAA,aAAa,UAAd;EAAuB,OAAO;YAC3B,OAAO,QAAQ,6BACd,iBAEA,iBAAA,GAAA,kBAAA,KAAC,sBAAA,eAAD;GACE,mBAAmB;GACnB,SAAA,QAAA,IAAA,aAC2B,gBACpB,UAAU;IACT,QAAQ,KACN,qIACF;IACA,QAAQ,KAAK,YAAY,MAAM,WAAW,MAAM,SAAS,GAAG;GAC9D,IACA,KAAA;aAGL;EACY,CAAA;CAEI,CAAA;AAE3B;;;;;;;;;;;;;AA0BA,SAAgB,gBAA8D;CAC5E,MAAM,SAAS,kBAAA,UAAU;CAEzB,IAAI,EAAE,+BAAA,YAAY,OAAO,WAAW;EAElC,CAAA,GAAA,sBAAA,UAAS,OAAO,OAAO,WAAW,aAAa,SAAS,IAAI;EAE5D,CAAA,GAAA,sBAAA,UAAS,OAAO,OAAO,mBAAmB,aAAa,UAAU,IAAI;EAErE,CAAA,GAAA,sBAAA,UAAS,OAAO,OAAO,SAAS,WAAW,MAAM;CACnD;CAEA,OAAO,MAAM,aAOT,SAGqE;EACrE,MAAM,EAAE,SAAS,eAAe,OAAO,eAAe,GAAG,SAAS;EAElE,OAAO,OAAO,WAAW,MAAa;GACpC;GACA;GACA;GACA;EACF,CAAC;CACH,GACA,CAAC,MAAM,CACT;AACF;;;;;;;;AA0BA,SAAgB,WAMd,OAA4E;CAE5E,MAAM,SADa,cACJ,EAAW,KAAY;CAEtC,IAAI,OAAO,MAAM,aAAa,YAC5B,OAAQ,MAAM,SAAiB,MAAM;CAGvC,OAAO,SAAS,MAAM,WAAW;AACnC;AAiBA,SAAgB,WAKd,MAEsC;CACtC,MAAM,SAAS,kBAAA,UAAmB;CAElC,IAAI,+BAAA,YAAY,OAAO,UAAU;EAC/B,MAAM,UAAU,OAAO,OAAO,QAAQ,IAAI;EAG1C,OAAQ,MAAM,SAAS,KAAK,OAAO,OAAO,IAAI;CAIhD;CAGA,QAAA,GAAA,sBAAA,UACE,OAAO,OAAO,SAEd,iBAAA,qBAAqB,MAAM,MAAM,CACnC;AACF;;;;;AAMA,SAAgB,iBAKd,MAEsC;CACtC,MAAM,iBAAiB,MAAM,WAAW,qBAAA,YAAY;CAEpD,OAAO,WAAW;EAChB,SAAS,YAAiD;GACxD,UAAU,QAAQ,MAChB,GACA,QAAQ,WAAW,MAAM,EAAE,YAAY,cAAc,CACvD;GACA,OAAO,MAAM,SAAS,KAAK,OAAO,OAAO,IAAI;EAC/C;EACA,mBAAmB,MAAM;CAC3B,CAAQ;AACV;;;;;AAMA,SAAgB,gBAKd,MAEsC;CACtC,MAAM,iBAAiB,MAAM,WAAW,qBAAA,YAAY;CAEpD,OAAO,WAAW;EAChB,SAAS,YAAiD;GACxD,UAAU,QAAQ,MAChB,QAAQ,WAAW,MAAM,EAAE,YAAY,cAAc,IAAI,CAC3D;GACA,OAAO,MAAM,SAAS,KAAK,OAAO,OAAO,IAAI;EAC/C;EACA,mBAAmB,MAAM;CAC3B,CAAQ;AACV"} |
@@ -49,21 +49,10 @@ import { StructuralSharingOption, ValidateSelected } from './structuralSharing.cjs'; | ||
| /** | ||
| * Read the full array of active route matches or select a derived subset. | ||
| * | ||
| * Useful for debugging, breadcrumbs, or aggregating metadata across matches. | ||
| * | ||
| * @returns The array of matches (or the selected value). | ||
| * @link https://tanstack.com/router/latest/docs/framework/react/api/router/useMatchesHook | ||
| * Read the presented route matches above the current match, or select a | ||
| * derived value from them. | ||
| */ | ||
| /** | ||
| * Read the full array of active route matches or select a derived subset. | ||
| * | ||
| * Useful for debugging, breadcrumbs, or aggregating metadata across matches. | ||
| * | ||
| * @link https://tanstack.com/router/latest/docs/framework/react/api/router/useMatchesHook | ||
| */ | ||
| export declare function useParentMatches<TRouter extends AnyRouter = RegisteredRouter, TSelected = unknown, TStructuralSharing extends boolean = boolean>(opts?: UseMatchesBaseOptions<TRouter, TSelected, TStructuralSharing> & StructuralSharingOption<TRouter, TSelected, TStructuralSharing>): UseMatchesResult<TRouter, TSelected>; | ||
| /** | ||
| * Read the array of active route matches that are children of the current | ||
| * match (or selected parent) in the match tree. | ||
| * Read the presented route matches below the current match, or select a | ||
| * derived value from them. | ||
| */ | ||
| export declare function useChildMatches<TRouter extends AnyRouter = RegisteredRouter, TSelected = unknown, TStructuralSharing extends boolean = boolean>(opts?: UseMatchesBaseOptions<TRouter, TSelected, TStructuralSharing> & StructuralSharingOption<TRouter, TSelected, TStructuralSharing>): UseMatchesResult<TRouter, TSelected>; |
@@ -7,5 +7,5 @@ const require_runtime = require("./_virtual/_rolldown/runtime.cjs"); | ||
| react = require_runtime.__toESM(react, 1); | ||
| let _tanstack_router_core_isServer = require("@tanstack/router-core/isServer"); | ||
| let react_jsx_runtime = require("react/jsx-runtime"); | ||
| let _tanstack_react_store = require("@tanstack/react-store"); | ||
| let _tanstack_router_core_isServer = require("@tanstack/router-core/isServer"); | ||
| //#region src/not-found.tsx | ||
@@ -12,0 +12,0 @@ function CatchNotFound(props) { |
@@ -31,4 +31,4 @@ "use client"; | ||
| /** | ||
| * Top-level component that renders the active route matches and provides the | ||
| * router to the React tree via context. | ||
| * Renders the current match presentation and provides the router to the React | ||
| * tree via context. | ||
| * | ||
@@ -35,0 +35,0 @@ * Accepts the same options as `createRouter` via props to update the router |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"RouterProvider.cjs","names":[],"sources":["../../src/RouterProvider.tsx"],"sourcesContent":["'use client'\n\nimport * as React from 'react'\nimport { hasKeys } from '@tanstack/router-core'\nimport { Matches } from './Matches'\nimport { routerContext } from './routerContext'\nimport type {\n AnyRouter,\n RegisteredRouter,\n RouterOptions,\n} from '@tanstack/router-core'\n\n/**\n * Low-level provider that places the router into React context and optionally\n * updates router options from props. Most apps should use `RouterProvider`.\n */\nexport function RouterContextProvider<\n TRouter extends AnyRouter = RegisteredRouter,\n TDehydrated extends Record<string, any> = Record<string, any>,\n>({\n router,\n children,\n ...rest\n}: RouterProps<TRouter, TDehydrated> & {\n children: React.ReactNode\n}) {\n if (hasKeys(rest)) {\n // Allow the router to update options on the router instance\n router.update({\n ...router.options,\n ...rest,\n context: {\n ...router.options.context,\n ...rest.context,\n },\n })\n }\n\n const provider = (\n <routerContext.Provider value={router as AnyRouter}>\n {children}\n </routerContext.Provider>\n )\n\n if (router.options.Wrap) {\n return <router.options.Wrap>{provider}</router.options.Wrap>\n }\n\n return provider\n}\n\n/**\n * Top-level component that renders the active route matches and provides the\n * router to the React tree via context.\n *\n * Accepts the same options as `createRouter` via props to update the router\n * instance after creation.\n *\n * @link https://tanstack.com/router/latest/docs/framework/react/api/router/createRouterFunction\n */\nexport function RouterProvider<\n TRouter extends AnyRouter = RegisteredRouter,\n TDehydrated extends Record<string, any> = Record<string, any>,\n>({ router, ...rest }: RouterProps<TRouter, TDehydrated>) {\n return (\n <RouterContextProvider router={router} {...rest}>\n <Matches />\n </RouterContextProvider>\n )\n}\n\nexport type RouterProps<\n TRouter extends AnyRouter = RegisteredRouter,\n TDehydrated extends Record<string, any> = Record<string, any>,\n> = Omit<\n RouterOptions<\n TRouter['routeTree'],\n NonNullable<TRouter['options']['trailingSlash']>,\n NonNullable<TRouter['options']['defaultStructuralSharing']>,\n TRouter['history'],\n TDehydrated\n >,\n 'context'\n> & {\n router: TRouter\n context?: Partial<\n RouterOptions<\n TRouter['routeTree'],\n NonNullable<TRouter['options']['trailingSlash']>,\n NonNullable<TRouter['options']['defaultStructuralSharing']>,\n TRouter['history'],\n TDehydrated\n >['context']\n >\n}\n"],"mappings":";;;;;;;;;;;;;AAgBA,SAAgB,sBAGd,EACA,QACA,UACA,GAAG,QAGF;CACD,KAAA,GAAA,sBAAA,SAAY,IAAI,GAEd,OAAO,OAAO;EACZ,GAAG,OAAO;EACV,GAAG;EACH,SAAS;GACP,GAAG,OAAO,QAAQ;GAClB,GAAG,KAAK;EACV;CACF,CAAC;CAGH,MAAM,WACJ,iBAAA,GAAA,kBAAA,KAAC,sBAAA,cAAc,UAAf;EAAwB,OAAO;EAC5B;CACqB,CAAA;CAG1B,IAAI,OAAO,QAAQ,MACjB,OAAO,iBAAA,GAAA,kBAAA,KAAC,OAAO,QAAQ,MAAhB,EAAA,UAAsB,SAA8B,CAAA;CAG7D,OAAO;AACT;;;;;;;;;;AAWA,SAAgB,eAGd,EAAE,QAAQ,GAAG,QAA2C;CACxD,OACE,iBAAA,GAAA,kBAAA,KAAC,uBAAD;EAA+B;EAAQ,GAAI;YACzC,iBAAA,GAAA,kBAAA,KAAC,gBAAA,SAAD,CAAU,CAAA;CACW,CAAA;AAE3B"} | ||
| {"version":3,"file":"RouterProvider.cjs","names":[],"sources":["../../src/RouterProvider.tsx"],"sourcesContent":["'use client'\n\nimport * as React from 'react'\nimport { hasKeys } from '@tanstack/router-core'\nimport { Matches } from './Matches'\nimport { routerContext } from './routerContext'\nimport type {\n AnyRouter,\n RegisteredRouter,\n RouterOptions,\n} from '@tanstack/router-core'\n\n/**\n * Low-level provider that places the router into React context and optionally\n * updates router options from props. Most apps should use `RouterProvider`.\n */\nexport function RouterContextProvider<\n TRouter extends AnyRouter = RegisteredRouter,\n TDehydrated extends Record<string, any> = Record<string, any>,\n>({\n router,\n children,\n ...rest\n}: RouterProps<TRouter, TDehydrated> & {\n children: React.ReactNode\n}) {\n if (hasKeys(rest)) {\n // Allow the router to update options on the router instance\n router.update({\n ...router.options,\n ...rest,\n context: {\n ...router.options.context,\n ...rest.context,\n },\n })\n }\n\n const provider = (\n <routerContext.Provider value={router as AnyRouter}>\n {children}\n </routerContext.Provider>\n )\n\n if (router.options.Wrap) {\n return <router.options.Wrap>{provider}</router.options.Wrap>\n }\n\n return provider\n}\n\n/**\n * Renders the current match presentation and provides the router to the React\n * tree via context.\n *\n * Accepts the same options as `createRouter` via props to update the router\n * instance after creation.\n *\n * @link https://tanstack.com/router/latest/docs/framework/react/api/router/createRouterFunction\n */\nexport function RouterProvider<\n TRouter extends AnyRouter = RegisteredRouter,\n TDehydrated extends Record<string, any> = Record<string, any>,\n>({ router, ...rest }: RouterProps<TRouter, TDehydrated>) {\n return (\n <RouterContextProvider router={router} {...rest}>\n <Matches />\n </RouterContextProvider>\n )\n}\n\nexport type RouterProps<\n TRouter extends AnyRouter = RegisteredRouter,\n TDehydrated extends Record<string, any> = Record<string, any>,\n> = Omit<\n RouterOptions<\n TRouter['routeTree'],\n NonNullable<TRouter['options']['trailingSlash']>,\n NonNullable<TRouter['options']['defaultStructuralSharing']>,\n TRouter['history'],\n TDehydrated\n >,\n 'context'\n> & {\n router: TRouter\n context?: Partial<\n RouterOptions<\n TRouter['routeTree'],\n NonNullable<TRouter['options']['trailingSlash']>,\n NonNullable<TRouter['options']['defaultStructuralSharing']>,\n TRouter['history'],\n TDehydrated\n >['context']\n >\n}\n"],"mappings":";;;;;;;;;;;;;AAgBA,SAAgB,sBAGd,EACA,QACA,UACA,GAAG,QAGF;CACD,KAAA,GAAA,sBAAA,SAAY,IAAI,GAEd,OAAO,OAAO;EACZ,GAAG,OAAO;EACV,GAAG;EACH,SAAS;GACP,GAAG,OAAO,QAAQ;GAClB,GAAG,KAAK;EACV;CACF,CAAC;CAGH,MAAM,WACJ,iBAAA,GAAA,kBAAA,KAAC,sBAAA,cAAc,UAAf;EAAwB,OAAO;EAC5B;CACqB,CAAA;CAG1B,IAAI,OAAO,QAAQ,MACjB,OAAO,iBAAA,GAAA,kBAAA,KAAC,OAAO,QAAQ,MAAhB,EAAA,UAAsB,SAA8B,CAAA;CAG7D,OAAO;AACT;;;;;;;;;;AAWA,SAAgB,eAGd,EAAE,QAAQ,GAAG,QAA2C;CACxD,OACE,iBAAA,GAAA,kBAAA,KAAC,uBAAD;EAA+B;EAAQ,GAAI;YACzC,iBAAA,GAAA,kBAAA,KAAC,gBAAA,SAAD,CAAU,CAAA;CACW,CAAA;AAE3B"} |
@@ -11,4 +11,4 @@ import { AnyRouter, RegisteredRouter, RouterOptions } from '@tanstack/router-core'; | ||
| /** | ||
| * Top-level component that renders the active route matches and provides the | ||
| * router to the React tree via context. | ||
| * Renders the current match presentation and provides the router to the React | ||
| * tree via context. | ||
| * | ||
@@ -15,0 +15,0 @@ * Accepts the same options as `createRouter` via props to update the router |
| let _tanstack_router_core = require("@tanstack/router-core"); | ||
| let _tanstack_router_core_isServer = require("@tanstack/router-core/isServer"); | ||
| let _tanstack_react_store = require("@tanstack/react-store"); | ||
| let _tanstack_router_core_isServer = require("@tanstack/router-core/isServer"); | ||
| //#region src/routerStores.ts | ||
@@ -5,0 +5,0 @@ var getStoreFactory = (opts) => { |
| const require_useRouter = require("./useRouter.cjs"); | ||
| let _tanstack_router_core_isServer = require("@tanstack/router-core/isServer"); | ||
| let react_jsx_runtime = require("react/jsx-runtime"); | ||
| let _tanstack_router_core_isServer = require("@tanstack/router-core/isServer"); | ||
| //#region src/ScriptOnce.tsx | ||
@@ -5,0 +5,0 @@ /** |
+22
-28
@@ -5,5 +5,5 @@ const require_useRouter = require("./useRouter.cjs"); | ||
| let react = require("react"); | ||
| let _tanstack_router_core_isServer = require("@tanstack/router-core/isServer"); | ||
| let react_jsx_runtime = require("react/jsx-runtime"); | ||
| let _tanstack_react_store = require("@tanstack/react-store"); | ||
| let _tanstack_router_core_isServer = require("@tanstack/router-core/isServer"); | ||
| //#region src/Scripts.tsx | ||
@@ -17,10 +17,19 @@ /** | ||
| const nonce = router.options.ssr?.nonce; | ||
| const getAssetScripts = (matches) => { | ||
| const assetScripts = []; | ||
| const getScripts = (matches) => { | ||
| matches = (0, _tanstack_router_core._getAssetMatches)(matches); | ||
| const scripts = matches.flatMap((match) => match.scripts ?? []).filter(Boolean).map(({ children, ...script }) => ({ | ||
| tag: "script", | ||
| attrs: { | ||
| ...script, | ||
| suppressHydrationWarning: true, | ||
| nonce | ||
| }, | ||
| children | ||
| })); | ||
| const manifest = router.ssr?.manifest; | ||
| if (!manifest) return []; | ||
| if (!manifest) return scripts; | ||
| for (const match of matches) { | ||
| const scripts = manifest.routes[match.routeId]?.scripts; | ||
| if (!scripts) continue; | ||
| for (const asset of scripts) assetScripts.push({ | ||
| const manifestScripts = manifest.routes[match.routeId]?.scripts; | ||
| if (!manifestScripts) continue; | ||
| for (const asset of manifestScripts) scripts.push({ | ||
| tag: "script", | ||
@@ -35,28 +44,13 @@ attrs: { | ||
| } | ||
| return assetScripts; | ||
| return scripts; | ||
| }; | ||
| const getScripts = (matches) => matches.map((match) => match.scripts).flat(1).filter(Boolean).map(({ children, ...script }) => ({ | ||
| tag: "script", | ||
| attrs: { | ||
| ...script, | ||
| suppressHydrationWarning: true, | ||
| nonce | ||
| }, | ||
| children | ||
| })); | ||
| if (_tanstack_router_core_isServer.isServer ?? router.isServer) { | ||
| const activeMatches = router.stores.matches.get(); | ||
| const assetScripts = getAssetScripts(activeMatches); | ||
| return renderScripts(router, getScripts(activeMatches), assetScripts); | ||
| } | ||
| const assetScripts = (0, _tanstack_react_store.useStore)(router.stores.matches, getAssetScripts, _tanstack_router_core.deepEqual); | ||
| return renderScripts(router, (0, _tanstack_react_store.useStore)(router.stores.matches, getScripts, _tanstack_router_core.deepEqual), assetScripts); | ||
| if (_tanstack_router_core_isServer.isServer ?? router.isServer) return renderScripts(router, getScripts(router.stores.matches.get())); | ||
| return renderScripts(router, (0, _tanstack_react_store.useStore)(router.stores.matches, getScripts, _tanstack_router_core.deepEqual)); | ||
| }; | ||
| function renderScripts(router, scripts, assetScripts) { | ||
| const allScripts = [...scripts, ...assetScripts]; | ||
| function renderScripts(router, scripts) { | ||
| if ((_tanstack_router_core_isServer.isServer ?? router.isServer) && router.serverSsr) { | ||
| const serverBufferedScript = router.serverSsr.takeBufferedScripts(); | ||
| if (serverBufferedScript) allScripts.unshift(serverBufferedScript); | ||
| if (serverBufferedScript) scripts.unshift(serverBufferedScript); | ||
| } | ||
| return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_jsx_runtime.Fragment, { children: allScripts.map((asset, i) => /* @__PURE__ */ (0, react.createElement)(require_Asset.Asset, { | ||
| return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_jsx_runtime.Fragment, { children: scripts.map((asset, i) => /* @__PURE__ */ (0, react.createElement)(require_Asset.Asset, { | ||
| ...asset, | ||
@@ -63,0 +57,0 @@ key: `tsr-scripts-${asset.tag}-${i}` |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"Scripts.cjs","names":[],"sources":["../../src/Scripts.tsx"],"sourcesContent":["import { useStore } from '@tanstack/react-store'\nimport { deepEqual } from '@tanstack/router-core'\nimport { isServer } from '@tanstack/router-core/isServer'\nimport { Asset } from './Asset'\nimport { useRouter } from './useRouter'\nimport type { RouterManagedTag } from '@tanstack/router-core'\n\ntype ScriptRenderAsset = RouterManagedTag & {\n preventScriptHoist?: boolean\n}\n\n/**\n * Render body script tags collected from route matches and SSR manifests.\n * Should be placed near the end of the document body.\n */\nexport const Scripts = () => {\n const router = useRouter()\n const nonce = router.options.ssr?.nonce\n\n const getAssetScripts = (matches: Array<any>) => {\n const assetScripts: Array<ScriptRenderAsset> = []\n const manifest = router.ssr?.manifest\n\n if (!manifest) {\n return []\n }\n\n for (const match of matches) {\n const scripts = manifest.routes[match.routeId]?.scripts\n\n if (!scripts) {\n continue\n }\n\n for (const asset of scripts) {\n assetScripts.push({\n tag: 'script',\n attrs: { ...asset.attrs, nonce },\n children: asset.children,\n ...(typeof asset.attrs?.src === 'string'\n ? { preventScriptHoist: true }\n : {}),\n })\n }\n }\n\n return assetScripts\n }\n\n const getScripts = (matches: Array<any>): Array<RouterManagedTag> =>\n (\n matches\n .map((match) => match.scripts!)\n .flat(1)\n .filter(Boolean) as Array<RouterManagedTag>\n ).map(\n ({ children, ...script }) =>\n ({\n tag: 'script',\n attrs: {\n ...script,\n suppressHydrationWarning: true,\n nonce,\n },\n children,\n }) satisfies RouterManagedTag,\n )\n\n if (isServer ?? router.isServer) {\n const activeMatches = router.stores.matches.get()\n const assetScripts = getAssetScripts(activeMatches)\n const scripts = getScripts(activeMatches)\n return renderScripts(router, scripts, assetScripts)\n }\n\n // eslint-disable-next-line react-hooks/rules-of-hooks -- condition is static\n const assetScripts = useStore(\n router.stores.matches,\n getAssetScripts,\n deepEqual,\n )\n // eslint-disable-next-line react-hooks/rules-of-hooks -- condition is static\n const scripts = useStore(router.stores.matches, getScripts, deepEqual)\n\n return renderScripts(router, scripts, assetScripts)\n}\n\nfunction renderScripts(\n router: ReturnType<typeof useRouter>,\n scripts: Array<RouterManagedTag>,\n assetScripts: Array<ScriptRenderAsset>,\n) {\n const allScripts = [...scripts, ...assetScripts] as Array<ScriptRenderAsset>\n\n if ((isServer ?? router.isServer) && router.serverSsr) {\n const serverBufferedScript = router.serverSsr.takeBufferedScripts()\n if (serverBufferedScript) {\n allScripts.unshift(serverBufferedScript)\n }\n }\n\n return (\n <>\n {allScripts.map((asset, i) => (\n <Asset {...asset} key={`tsr-scripts-${asset.tag}-${i}`} />\n ))}\n </>\n )\n}\n"],"mappings":";;;;;;;;;;;;AAeA,IAAa,gBAAgB;CAC3B,MAAM,SAAS,kBAAA,UAAU;CACzB,MAAM,QAAQ,OAAO,QAAQ,KAAK;CAElC,MAAM,mBAAmB,YAAwB;EAC/C,MAAM,eAAyC,CAAC;EAChD,MAAM,WAAW,OAAO,KAAK;EAE7B,IAAI,CAAC,UACH,OAAO,CAAC;EAGV,KAAK,MAAM,SAAS,SAAS;GAC3B,MAAM,UAAU,SAAS,OAAO,MAAM,UAAU;GAEhD,IAAI,CAAC,SACH;GAGF,KAAK,MAAM,SAAS,SAClB,aAAa,KAAK;IAChB,KAAK;IACL,OAAO;KAAE,GAAG,MAAM;KAAO;IAAM;IAC/B,UAAU,MAAM;IAChB,GAAI,OAAO,MAAM,OAAO,QAAQ,WAC5B,EAAE,oBAAoB,KAAK,IAC3B,CAAC;GACP,CAAC;EAEL;EAEA,OAAO;CACT;CAEA,MAAM,cAAc,YAEhB,QACG,KAAK,UAAU,MAAM,OAAQ,EAC7B,KAAK,CAAC,EACN,OAAO,OAAO,EACjB,KACC,EAAE,UAAU,GAAG,cACb;EACC,KAAK;EACL,OAAO;GACL,GAAG;GACH,0BAA0B;GAC1B;EACF;EACA;CACF,EACJ;CAEF,IAAI,+BAAA,YAAY,OAAO,UAAU;EAC/B,MAAM,gBAAgB,OAAO,OAAO,QAAQ,IAAI;EAChD,MAAM,eAAe,gBAAgB,aAAa;EAElD,OAAO,cAAc,QADL,WAAW,aACE,GAAS,YAAY;CACpD;CAGA,MAAM,gBAAA,GAAA,sBAAA,UACJ,OAAO,OAAO,SACd,iBACA,sBAAA,SACF;CAIA,OAAO,cAAc,SAAA,GAAA,sBAAA,UAFI,OAAO,OAAO,SAAS,YAAY,sBAAA,SAE/B,GAAS,YAAY;AACpD;AAEA,SAAS,cACP,QACA,SACA,cACA;CACA,MAAM,aAAa,CAAC,GAAG,SAAS,GAAG,YAAY;CAE/C,KAAK,+BAAA,YAAY,OAAO,aAAa,OAAO,WAAW;EACrD,MAAM,uBAAuB,OAAO,UAAU,oBAAoB;EAClE,IAAI,sBACF,WAAW,QAAQ,oBAAoB;CAE3C;CAEA,OACE,iBAAA,GAAA,kBAAA,KAAA,kBAAA,UAAA,EAAA,UACG,WAAW,KAAK,OAAO,MACtB,iBAAA,GAAA,MAAA,eAAC,cAAA,OAAD;EAAO,GAAI;EAAO,KAAK,eAAe,MAAM,IAAI,GAAG;CAAM,CAAA,CAC1D,EACD,CAAA;AAEN"} | ||
| {"version":3,"file":"Scripts.cjs","names":[],"sources":["../../src/Scripts.tsx"],"sourcesContent":["import { useStore } from '@tanstack/react-store'\nimport { _getAssetMatches, deepEqual } from '@tanstack/router-core'\nimport { isServer } from '@tanstack/router-core/isServer'\nimport { Asset } from './Asset'\nimport { useRouter } from './useRouter'\nimport type { RouterManagedTag } from '@tanstack/router-core'\n\ntype ScriptRenderAsset = RouterManagedTag & {\n preventScriptHoist?: boolean\n}\n\n/**\n * Render body script tags collected from route matches and SSR manifests.\n * Should be placed near the end of the document body.\n */\nexport const Scripts = () => {\n const router = useRouter()\n const nonce = router.options.ssr?.nonce\n\n const getScripts = (matches: Array<any>) => {\n matches = _getAssetMatches(matches)\n const scripts = matches\n .flatMap((match) => match.scripts ?? [])\n .filter(Boolean)\n .map(\n ({ children, ...script }) =>\n ({\n tag: 'script',\n attrs: {\n ...script,\n suppressHydrationWarning: true,\n nonce,\n },\n children,\n }) satisfies RouterManagedTag,\n ) as Array<ScriptRenderAsset>\n const manifest = router.ssr?.manifest\n\n if (!manifest) {\n return scripts\n }\n\n for (const match of matches) {\n const manifestScripts = manifest.routes[match.routeId]?.scripts\n\n if (!manifestScripts) {\n continue\n }\n\n for (const asset of manifestScripts) {\n scripts.push({\n tag: 'script',\n attrs: { ...asset.attrs, nonce },\n children: asset.children,\n ...(typeof asset.attrs?.src === 'string'\n ? { preventScriptHoist: true }\n : {}),\n })\n }\n }\n\n return scripts\n }\n\n if (isServer ?? router.isServer) {\n const activeMatches = router.stores.matches.get()\n const scripts = getScripts(activeMatches)\n return renderScripts(router, scripts)\n }\n\n // eslint-disable-next-line react-hooks/rules-of-hooks -- condition is static\n const scripts = useStore(router.stores.matches, getScripts, deepEqual)\n\n return renderScripts(router, scripts)\n}\n\nfunction renderScripts(\n router: ReturnType<typeof useRouter>,\n scripts: Array<ScriptRenderAsset>,\n) {\n if ((isServer ?? router.isServer) && router.serverSsr) {\n const serverBufferedScript = router.serverSsr.takeBufferedScripts()\n if (serverBufferedScript) {\n scripts.unshift(serverBufferedScript)\n }\n }\n\n return (\n <>\n {scripts.map((asset, i) => (\n <Asset {...asset} key={`tsr-scripts-${asset.tag}-${i}`} />\n ))}\n </>\n )\n}\n"],"mappings":";;;;;;;;;;;;AAeA,IAAa,gBAAgB;CAC3B,MAAM,SAAS,kBAAA,UAAU;CACzB,MAAM,QAAQ,OAAO,QAAQ,KAAK;CAElC,MAAM,cAAc,YAAwB;EAC1C,WAAA,GAAA,sBAAA,kBAA2B,OAAO;EAClC,MAAM,UAAU,QACb,SAAS,UAAU,MAAM,WAAW,CAAC,CAAC,EACtC,OAAO,OAAO,EACd,KACE,EAAE,UAAU,GAAG,cACb;GACC,KAAK;GACL,OAAO;IACL,GAAG;IACH,0BAA0B;IAC1B;GACF;GACA;EACF,EACJ;EACF,MAAM,WAAW,OAAO,KAAK;EAE7B,IAAI,CAAC,UACH,OAAO;EAGT,KAAK,MAAM,SAAS,SAAS;GAC3B,MAAM,kBAAkB,SAAS,OAAO,MAAM,UAAU;GAExD,IAAI,CAAC,iBACH;GAGF,KAAK,MAAM,SAAS,iBAClB,QAAQ,KAAK;IACX,KAAK;IACL,OAAO;KAAE,GAAG,MAAM;KAAO;IAAM;IAC/B,UAAU,MAAM;IAChB,GAAI,OAAO,MAAM,OAAO,QAAQ,WAC5B,EAAE,oBAAoB,KAAK,IAC3B,CAAC;GACP,CAAC;EAEL;EAEA,OAAO;CACT;CAEA,IAAI,+BAAA,YAAY,OAAO,UAGrB,OAAO,cAAc,QADL,WADM,OAAO,OAAO,QAAQ,IACjB,CACE,CAAO;CAMtC,OAAO,cAAc,SAAA,GAAA,sBAAA,UAFI,OAAO,OAAO,SAAS,YAAY,sBAAA,SAE/B,CAAO;AACtC;AAEA,SAAS,cACP,QACA,SACA;CACA,KAAK,+BAAA,YAAY,OAAO,aAAa,OAAO,WAAW;EACrD,MAAM,uBAAuB,OAAO,UAAU,oBAAoB;EAClE,IAAI,sBACF,QAAQ,QAAQ,oBAAoB;CAExC;CAEA,OACE,iBAAA,GAAA,kBAAA,KAAA,kBAAA,UAAA,EAAA,UACG,QAAQ,KAAK,OAAO,MACnB,iBAAA,GAAA,MAAA,eAAC,cAAA,OAAD;EAAO,GAAI;EAAO,KAAK,eAAe,MAAM,IAAI,GAAG;CAAM,CAAA,CAC1D,EACD,CAAA;AAEN"} |
@@ -34,5 +34,8 @@ const require_runtime = require("../_virtual/_rolldown/runtime.cjs"); | ||
| if ((0, isbot.isbot)(request.headers.get("User-Agent"))) await waitForReadyOrAbort(stream.allReady, request.signal); | ||
| const responseStream = (0, _tanstack_router_core_ssr_server.transformReadableStreamWithRouter)(router, stream, { onAbort: () => stream.cancel().catch(() => {}) }); | ||
| const responseStream = (0, _tanstack_router_core_ssr_server.transformReadableStreamWithRouter)(router, stream, { | ||
| signal: request.signal, | ||
| onAbort: () => stream.cancel().catch(() => {}) | ||
| }); | ||
| return (0, _tanstack_router_core_ssr_server.createSsrStreamResponse)(router, new Response(responseStream, { | ||
| status: router.stores.statusCode.get(), | ||
| status: router._serverResult?.type === "render" ? router._serverResult.status : 200, | ||
| headers: responseHeaders | ||
@@ -93,3 +96,6 @@ })); | ||
| } | ||
| const responseStream = (0, _tanstack_router_core_ssr_server.transformPipeableStreamWithRouter)(router, reactAppPassthrough, { onAbort: abortPipeable }); | ||
| const responseStream = (0, _tanstack_router_core_ssr_server.transformPipeableStreamWithRouter)(router, reactAppPassthrough, { | ||
| signal: request.signal, | ||
| onAbort: abortPipeable | ||
| }); | ||
| responseAttached = true; | ||
@@ -101,3 +107,3 @@ if (endedBeforeAttach) reactAppPassthrough.destroy(pendingDestroyError()); | ||
| return (0, _tanstack_router_core_ssr_server.createSsrStreamResponse)(router, new Response(responseStream, { | ||
| status: router.stores.statusCode.get(), | ||
| status: router._serverResult?.type === "render" ? router._serverResult.status : 200, | ||
| headers: responseHeaders | ||
@@ -104,0 +110,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\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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"} | ||
| {"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 {\n signal: request.signal,\n onAbort: () => stream.cancel().catch(() => {}),\n },\n )\n return createSsrStreamResponse(\n router,\n new Response(responseStream as any, {\n status:\n router._serverResult?.type === 'render'\n ? router._serverResult.status\n : 200,\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 { signal: request.signal, 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:\n router._serverResult?.type === 'render'\n ? router._serverResult.status\n : 200,\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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"} |
@@ -12,3 +12,3 @@ const require_runtime = require("../_virtual/_rolldown/runtime.cjs"); | ||
| return new Response(`<!DOCTYPE html>${html}`, { | ||
| status: router.stores.statusCode.get(), | ||
| status: router._serverResult?.type === "render" ? router._serverResult.status : 200, | ||
| headers: responseHeaders | ||
@@ -15,0 +15,0 @@ }); |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"renderRouterToString.cjs","names":[],"sources":["../../../src/ssr/renderRouterToString.tsx"],"sourcesContent":["import ReactDOMServer from 'react-dom/server'\nimport type { ReactNode } from 'react'\nimport type { AnyRouter } from '@tanstack/router-core'\n\nexport const renderRouterToString = async ({\n router,\n responseHeaders,\n children,\n}: {\n router: AnyRouter\n responseHeaders: Headers\n children: ReactNode\n}) => {\n try {\n let html = ReactDOMServer.renderToString(children)\n router.serverSsr!.setRenderFinished()\n\n const injectedHtml = router.serverSsr!.takeBufferedHtml()\n if (injectedHtml) {\n html = html.replace(`</body>`, () => `${injectedHtml}</body>`)\n }\n\n return new Response(`<!DOCTYPE html>${html}`, {\n status: router.stores.statusCode.get(),\n headers: responseHeaders,\n })\n } catch (error) {\n console.error('Render to string error:', error)\n return new Response('Internal Server Error', {\n status: 500,\n headers: responseHeaders,\n })\n } finally {\n router.serverSsr?.cleanup()\n }\n}\n"],"mappings":";;;;AAIA,IAAa,uBAAuB,OAAO,EACzC,QACA,iBACA,eAKI;CACJ,IAAI;EACF,IAAI,OAAO,iBAAA,QAAe,eAAe,QAAQ;EACjD,OAAO,UAAW,kBAAkB;EAEpC,MAAM,eAAe,OAAO,UAAW,iBAAiB;EACxD,IAAI,cACF,OAAO,KAAK,QAAQ,iBAAiB,GAAG,aAAa,QAAQ;EAG/D,OAAO,IAAI,SAAS,kBAAkB,QAAQ;GAC5C,QAAQ,OAAO,OAAO,WAAW,IAAI;GACrC,SAAS;EACX,CAAC;CACH,SAAS,OAAO;EACd,QAAQ,MAAM,2BAA2B,KAAK;EAC9C,OAAO,IAAI,SAAS,yBAAyB;GAC3C,QAAQ;GACR,SAAS;EACX,CAAC;CACH,UAAU;EACR,OAAO,WAAW,QAAQ;CAC5B;AACF"} | ||
| {"version":3,"file":"renderRouterToString.cjs","names":[],"sources":["../../../src/ssr/renderRouterToString.tsx"],"sourcesContent":["import ReactDOMServer from 'react-dom/server'\nimport type { ReactNode } from 'react'\nimport type { AnyRouter } from '@tanstack/router-core'\n\nexport const renderRouterToString = async ({\n router,\n responseHeaders,\n children,\n}: {\n router: AnyRouter\n responseHeaders: Headers\n children: ReactNode\n}) => {\n try {\n let html = ReactDOMServer.renderToString(children)\n router.serverSsr!.setRenderFinished()\n\n const injectedHtml = router.serverSsr!.takeBufferedHtml()\n if (injectedHtml) {\n html = html.replace(`</body>`, () => `${injectedHtml}</body>`)\n }\n\n return new Response(`<!DOCTYPE html>${html}`, {\n status:\n router._serverResult?.type === 'render'\n ? router._serverResult.status\n : 200,\n headers: responseHeaders,\n })\n } catch (error) {\n console.error('Render to string error:', error)\n return new Response('Internal Server Error', {\n status: 500,\n headers: responseHeaders,\n })\n } finally {\n router.serverSsr?.cleanup()\n }\n}\n"],"mappings":";;;;AAIA,IAAa,uBAAuB,OAAO,EACzC,QACA,iBACA,eAKI;CACJ,IAAI;EACF,IAAI,OAAO,iBAAA,QAAe,eAAe,QAAQ;EACjD,OAAO,UAAW,kBAAkB;EAEpC,MAAM,eAAe,OAAO,UAAW,iBAAiB;EACxD,IAAI,cACF,OAAO,KAAK,QAAQ,iBAAiB,GAAG,aAAa,QAAQ;EAG/D,OAAO,IAAI,SAAS,kBAAkB,QAAQ;GAC5C,QACE,OAAO,eAAe,SAAS,WAC3B,OAAO,cAAc,SACrB;GACN,SAAS;EACX,CAAC;CACH,SAAS,OAAO;EACd,QAAQ,MAAM,2BAA2B,KAAK;EAC9C,OAAO,IAAI,SAAS,yBAAyB;GAC3C,QAAQ;GACR,SAAS;EACX,CAAC;CACH,UAAU;EACR,OAAO,WAAW,QAAQ;CAC5B;AACF"} |
@@ -8,4 +8,3 @@ const require_awaited = require("../awaited.cjs"); | ||
| function RouterClient(props) { | ||
| if (!hydrationPromise) if (!props.router.stores.matchesId.get().length) hydrationPromise = (0, _tanstack_router_core_ssr_client.hydrate)(props.router); | ||
| else hydrationPromise = Promise.resolve(); | ||
| hydrationPromise ??= (0, _tanstack_router_core_ssr_client.hydrate)(props.router).finally(() => window.$_TSR.h()); | ||
| return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_awaited.Await, { | ||
@@ -12,0 +11,0 @@ promise: hydrationPromise, |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"RouterClient.cjs","names":[],"sources":["../../../src/ssr/RouterClient.tsx"],"sourcesContent":["import { hydrate } from '@tanstack/router-core/ssr/client'\nimport { Await } from '../awaited'\nimport { RouterProvider } from '../RouterProvider'\nimport type { AnyRouter } from '@tanstack/router-core'\n\nlet hydrationPromise: Promise<void | Array<Array<void>>> | undefined\n\nexport function RouterClient(props: { router: AnyRouter }) {\n if (!hydrationPromise) {\n if (!props.router.stores.matchesId.get().length) {\n hydrationPromise = hydrate(props.router)\n } else {\n hydrationPromise = Promise.resolve()\n }\n }\n return (\n <Await\n promise={hydrationPromise}\n children={() => <RouterProvider router={props.router} />}\n />\n )\n}\n"],"mappings":";;;;;AAKA,IAAI;AAEJ,SAAgB,aAAa,OAA8B;CACzD,IAAI,CAAC,kBACH,IAAI,CAAC,MAAM,OAAO,OAAO,UAAU,IAAI,EAAE,QACvC,oBAAA,GAAA,iCAAA,SAA2B,MAAM,MAAM;MAEvC,mBAAmB,QAAQ,QAAQ;CAGvC,OACE,iBAAA,GAAA,kBAAA,KAAC,gBAAA,OAAD;EACE,SAAS;EACT,gBAAgB,iBAAA,GAAA,kBAAA,KAAC,uBAAA,gBAAD,EAAgB,QAAQ,MAAM,OAAS,CAAA;CACxD,CAAA;AAEL"} | ||
| {"version":3,"file":"RouterClient.cjs","names":[],"sources":["../../../src/ssr/RouterClient.tsx"],"sourcesContent":["import { hydrate } from '@tanstack/router-core/ssr/client'\nimport { Await } from '../awaited'\nimport { RouterProvider } from '../RouterProvider'\nimport type { AnyRouter } from '@tanstack/router-core'\n\nlet hydrationPromise: Promise<void> | undefined\n\nexport function RouterClient(props: { router: AnyRouter }) {\n hydrationPromise ??= hydrate(props.router).finally(() => window.$_TSR!.h())\n\n return (\n <Await\n promise={hydrationPromise}\n children={() => <RouterProvider router={props.router} />}\n />\n )\n}\n"],"mappings":";;;;;AAKA,IAAI;AAEJ,SAAgB,aAAa,OAA8B;CACzD,sBAAA,GAAA,iCAAA,SAA6B,MAAM,MAAM,EAAE,cAAc,OAAO,MAAO,EAAE,CAAC;CAE1E,OACE,iBAAA,GAAA,kBAAA,KAAC,gBAAA,OAAD;EACE,SAAS;EACT,gBAAgB,iBAAA,GAAA,kBAAA,KAAC,uBAAA,gBAAD,EAAgB,QAAQ,MAAM,OAAS,CAAA;CACxD,CAAA;AAEL"} |
@@ -8,29 +8,47 @@ "use client"; | ||
| react = require_runtime.__toESM(react, 1); | ||
| let _tanstack_react_store = require("@tanstack/react-store"); | ||
| //#region src/Transitioner.tsx | ||
| function Transitioner() { | ||
| const router = require_useRouter.useRouter(); | ||
| const mountLoadForRouter = react.useRef({ | ||
| router, | ||
| mounted: false | ||
| const acknowledgement = react.useRef(void 0); | ||
| const mounted = process.env.NODE_ENV !== "production" ? react.useRef(false) : void 0; | ||
| router._rendered = (matches) => { | ||
| const current = acknowledgement.current; | ||
| if (current?.[0].length === matches.length && current[0].every((match, index) => match.id === matches[index].id && match.abortController === matches[index].abortController && match.status === matches[index].status)) { | ||
| acknowledgement.current = void 0; | ||
| current[1](true); | ||
| } | ||
| }; | ||
| if (process.env.NODE_ENV === "production") router.startTransition = (fn, expected, urgent) => new Promise((resolve) => { | ||
| acknowledgement.current?.[1](false); | ||
| acknowledgement.current = [expected, resolve]; | ||
| if (urgent) fn(); | ||
| else react.startTransition(fn); | ||
| }); | ||
| const [isTransitioning, setIsTransitioning] = react.useState(false); | ||
| const isLoading = (0, _tanstack_react_store.useStore)(router.stores.isLoading, (value) => value); | ||
| const hasPending = (0, _tanstack_react_store.useStore)(router.stores.hasPending, (value) => value); | ||
| const previousIsLoading = require_utils.usePrevious(isLoading); | ||
| const isAnyPending = isLoading || isTransitioning || hasPending; | ||
| const previousIsAnyPending = require_utils.usePrevious(isAnyPending); | ||
| const isPagePending = isLoading || hasPending; | ||
| const previousIsPagePending = require_utils.usePrevious(isPagePending); | ||
| router.startTransition = (fn) => { | ||
| setIsTransitioning(true); | ||
| react.startTransition(() => { | ||
| fn(); | ||
| setIsTransitioning(false); | ||
| else { | ||
| router.startTransition = (fn, expected, urgent) => new Promise((resolve, reject) => { | ||
| acknowledgement.current?.[1](false); | ||
| const next = [expected, resolve]; | ||
| acknowledgement.current = next; | ||
| try { | ||
| if (urgent) fn(); | ||
| else react.startTransition(fn); | ||
| } catch (cause) { | ||
| if (acknowledgement.current === next) acknowledgement.current = void 0; | ||
| reject(cause); | ||
| } | ||
| }); | ||
| }; | ||
| react.useEffect(() => { | ||
| router._cancelTransition = () => { | ||
| const current = acknowledgement.current; | ||
| acknowledgement.current = void 0; | ||
| current?.[1](false); | ||
| }; | ||
| } | ||
| require_utils.useLayoutEffect(() => { | ||
| const unsub = router.history.subscribe(router.load); | ||
| if (mounted?.current) return unsub; | ||
| if (mounted) mounted.current = true; | ||
| router.updateLatestLocation(); | ||
| const location = router.latestLocation; | ||
| const nextLocation = router.buildLocation({ | ||
| to: router.latestLocation.pathname, | ||
| to: location.pathname, | ||
| search: true, | ||
@@ -42,62 +60,20 @@ params: true, | ||
| }); | ||
| if ((0, _tanstack_router_core.trimPathRight)(router.latestLocation.publicHref) !== (0, _tanstack_router_core.trimPathRight)(nextLocation.publicHref)) router.commitLocation({ | ||
| ...nextLocation, | ||
| replace: true | ||
| }); | ||
| return () => { | ||
| unsub(); | ||
| }; | ||
| }, [router, router.history]); | ||
| require_utils.useLayoutEffect(() => { | ||
| if (typeof window !== "undefined" && router.ssr || mountLoadForRouter.current.router === router && mountLoadForRouter.current.mounted) return; | ||
| mountLoadForRouter.current = { | ||
| router, | ||
| mounted: true | ||
| }; | ||
| const tryLoad = async () => { | ||
| try { | ||
| await router.load(); | ||
| } catch (err) { | ||
| console.error(err); | ||
| } | ||
| }; | ||
| tryLoad(); | ||
| }, [router]); | ||
| require_utils.useLayoutEffect(() => { | ||
| if (previousIsLoading && !isLoading) router.emit({ | ||
| type: "onLoad", | ||
| ...(0, _tanstack_router_core.getLocationChangeInfo)(router.stores.location.get(), router.stores.resolvedLocation.get()) | ||
| }); | ||
| }, [ | ||
| previousIsLoading, | ||
| router, | ||
| isLoading | ||
| ]); | ||
| require_utils.useLayoutEffect(() => { | ||
| if (previousIsPagePending && !isPagePending) router.emit({ | ||
| type: "onBeforeRouteMount", | ||
| ...(0, _tanstack_router_core.getLocationChangeInfo)(router.stores.location.get(), router.stores.resolvedLocation.get()) | ||
| }); | ||
| }, [ | ||
| isPagePending, | ||
| previousIsPagePending, | ||
| router | ||
| ]); | ||
| require_utils.useLayoutEffect(() => { | ||
| if (previousIsAnyPending && !isAnyPending) { | ||
| const changeInfo = (0, _tanstack_router_core.getLocationChangeInfo)(router.stores.location.get(), router.stores.resolvedLocation.get()); | ||
| router.emit({ | ||
| type: "onResolved", | ||
| ...changeInfo | ||
| if ((0, _tanstack_router_core.trimPathRight)(location.publicHref) !== (0, _tanstack_router_core.trimPathRight)(nextLocation.publicHref)) { | ||
| router.commitLocation({ | ||
| ...nextLocation, | ||
| replace: true, | ||
| ignoreBlocker: true | ||
| }); | ||
| (0, _tanstack_react_store.batch)(() => { | ||
| router.stores.status.set("idle"); | ||
| router.stores.resolvedLocation.set(router.stores.location.get()); | ||
| return unsub; | ||
| } | ||
| const resolvedLocation = router.stores.resolvedLocation.get(); | ||
| if (resolvedLocation?.href === location.href && resolvedLocation.state.__TSR_key === location.state.__TSR_key) acknowledgement.current = [router.stores.matches.get(), (rendered) => { | ||
| if (rendered) router.emit({ | ||
| type: "onRendered", | ||
| ...(0, _tanstack_router_core.getLocationChangeInfo)(resolvedLocation, resolvedLocation) | ||
| }); | ||
| } | ||
| }, [ | ||
| isAnyPending, | ||
| previousIsAnyPending, | ||
| router | ||
| ]); | ||
| }]; | ||
| else if (!router._tx) router.load().catch(console.error); | ||
| return unsub; | ||
| }, [router, router.history]); | ||
| return null; | ||
@@ -104,0 +80,0 @@ } |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"Transitioner.cjs","names":[],"sources":["../../src/Transitioner.tsx"],"sourcesContent":["'use client'\n\nimport * as React from 'react'\nimport { batch, useStore } from '@tanstack/react-store'\nimport { getLocationChangeInfo, trimPathRight } from '@tanstack/router-core'\nimport { useLayoutEffect, usePrevious } from './utils'\nimport { useRouter } from './useRouter'\n\nexport function Transitioner() {\n const router = useRouter()\n const mountLoadForRouter = React.useRef({ router, mounted: false })\n\n const [isTransitioning, setIsTransitioning] = React.useState(false)\n // Track pending state changes\n const isLoading = useStore(router.stores.isLoading, (value) => value)\n const hasPending = useStore(router.stores.hasPending, (value) => value)\n\n const previousIsLoading = usePrevious(isLoading)\n\n const isAnyPending = isLoading || isTransitioning || hasPending\n const previousIsAnyPending = usePrevious(isAnyPending)\n\n const isPagePending = isLoading || hasPending\n const previousIsPagePending = usePrevious(isPagePending)\n\n router.startTransition = (fn: () => void) => {\n setIsTransitioning(true)\n React.startTransition(() => {\n fn()\n setIsTransitioning(false)\n })\n }\n\n // Subscribe to location changes\n // and try to load the new location\n React.useEffect(() => {\n const unsub = router.history.subscribe(router.load)\n\n const nextLocation = router.buildLocation({\n to: router.latestLocation.pathname,\n search: true,\n params: true,\n hash: true,\n state: true,\n _includeValidateSearch: true,\n })\n\n // Check if the current URL matches the canonical form.\n // Compare publicHref (browser-facing URL) for consistency with\n // the server-side redirect check in router.beforeLoad.\n if (\n trimPathRight(router.latestLocation.publicHref) !==\n trimPathRight(nextLocation.publicHref)\n ) {\n router.commitLocation({ ...nextLocation, replace: true })\n }\n\n return () => {\n unsub()\n }\n }, [router, router.history])\n\n // Try to load the initial location\n useLayoutEffect(() => {\n if (\n // if we are hydrating from SSR, loading is triggered in ssr-client\n (typeof window !== 'undefined' && router.ssr) ||\n (mountLoadForRouter.current.router === router &&\n mountLoadForRouter.current.mounted)\n ) {\n return\n }\n mountLoadForRouter.current = { router, mounted: true }\n\n const tryLoad = async () => {\n try {\n await router.load()\n } catch (err) {\n console.error(err)\n }\n }\n\n tryLoad()\n }, [router])\n\n useLayoutEffect(() => {\n // The router was loading and now it's not\n if (previousIsLoading && !isLoading) {\n router.emit({\n type: 'onLoad', // When the new URL has committed, when the new matches have been loaded into state.matches\n ...getLocationChangeInfo(\n router.stores.location.get(),\n router.stores.resolvedLocation.get(),\n ),\n })\n }\n }, [previousIsLoading, router, isLoading])\n\n useLayoutEffect(() => {\n // emit onBeforeRouteMount\n if (previousIsPagePending && !isPagePending) {\n router.emit({\n type: 'onBeforeRouteMount',\n ...getLocationChangeInfo(\n router.stores.location.get(),\n router.stores.resolvedLocation.get(),\n ),\n })\n }\n }, [isPagePending, previousIsPagePending, router])\n\n useLayoutEffect(() => {\n if (previousIsAnyPending && !isAnyPending) {\n const changeInfo = getLocationChangeInfo(\n router.stores.location.get(),\n router.stores.resolvedLocation.get(),\n )\n router.emit({\n type: 'onResolved',\n ...changeInfo,\n })\n\n batch(() => {\n router.stores.status.set('idle')\n router.stores.resolvedLocation.set(router.stores.location.get())\n })\n }\n }, [isAnyPending, previousIsAnyPending, router])\n\n return null\n}\n"],"mappings":";;;;;;;;;AAQA,SAAgB,eAAe;CAC7B,MAAM,SAAS,kBAAA,UAAU;CACzB,MAAM,qBAAqB,MAAM,OAAO;EAAE;EAAQ,SAAS;CAAM,CAAC;CAElE,MAAM,CAAC,iBAAiB,sBAAsB,MAAM,SAAS,KAAK;CAElE,MAAM,aAAA,GAAA,sBAAA,UAAqB,OAAO,OAAO,YAAY,UAAU,KAAK;CACpE,MAAM,cAAA,GAAA,sBAAA,UAAsB,OAAO,OAAO,aAAa,UAAU,KAAK;CAEtE,MAAM,oBAAoB,cAAA,YAAY,SAAS;CAE/C,MAAM,eAAe,aAAa,mBAAmB;CACrD,MAAM,uBAAuB,cAAA,YAAY,YAAY;CAErD,MAAM,gBAAgB,aAAa;CACnC,MAAM,wBAAwB,cAAA,YAAY,aAAa;CAEvD,OAAO,mBAAmB,OAAmB;EAC3C,mBAAmB,IAAI;EACvB,MAAM,sBAAsB;GAC1B,GAAG;GACH,mBAAmB,KAAK;EAC1B,CAAC;CACH;CAIA,MAAM,gBAAgB;EACpB,MAAM,QAAQ,OAAO,QAAQ,UAAU,OAAO,IAAI;EAElD,MAAM,eAAe,OAAO,cAAc;GACxC,IAAI,OAAO,eAAe;GAC1B,QAAQ;GACR,QAAQ;GACR,MAAM;GACN,OAAO;GACP,wBAAwB;EAC1B,CAAC;EAKD,KAAA,GAAA,sBAAA,eACgB,OAAO,eAAe,UAAU,OAAA,GAAA,sBAAA,eAChC,aAAa,UAAU,GAErC,OAAO,eAAe;GAAE,GAAG;GAAc,SAAS;EAAK,CAAC;EAG1D,aAAa;GACX,MAAM;EACR;CACF,GAAG,CAAC,QAAQ,OAAO,OAAO,CAAC;CAG3B,cAAA,sBAAsB;EACpB,IAEG,OAAO,WAAW,eAAe,OAAO,OACxC,mBAAmB,QAAQ,WAAW,UACrC,mBAAmB,QAAQ,SAE7B;EAEF,mBAAmB,UAAU;GAAE;GAAQ,SAAS;EAAK;EAErD,MAAM,UAAU,YAAY;GAC1B,IAAI;IACF,MAAM,OAAO,KAAK;GACpB,SAAS,KAAK;IACZ,QAAQ,MAAM,GAAG;GACnB;EACF;EAEA,QAAQ;CACV,GAAG,CAAC,MAAM,CAAC;CAEX,cAAA,sBAAsB;EAEpB,IAAI,qBAAqB,CAAC,WACxB,OAAO,KAAK;GACV,MAAM;GACN,IAAA,GAAA,sBAAA,uBACE,OAAO,OAAO,SAAS,IAAI,GAC3B,OAAO,OAAO,iBAAiB,IAAI,CACrC;EACF,CAAC;CAEL,GAAG;EAAC;EAAmB;EAAQ;CAAS,CAAC;CAEzC,cAAA,sBAAsB;EAEpB,IAAI,yBAAyB,CAAC,eAC5B,OAAO,KAAK;GACV,MAAM;GACN,IAAA,GAAA,sBAAA,uBACE,OAAO,OAAO,SAAS,IAAI,GAC3B,OAAO,OAAO,iBAAiB,IAAI,CACrC;EACF,CAAC;CAEL,GAAG;EAAC;EAAe;EAAuB;CAAM,CAAC;CAEjD,cAAA,sBAAsB;EACpB,IAAI,wBAAwB,CAAC,cAAc;GACzC,MAAM,cAAA,GAAA,sBAAA,uBACJ,OAAO,OAAO,SAAS,IAAI,GAC3B,OAAO,OAAO,iBAAiB,IAAI,CACrC;GACA,OAAO,KAAK;IACV,MAAM;IACN,GAAG;GACL,CAAC;GAED,CAAA,GAAA,sBAAA,aAAY;IACV,OAAO,OAAO,OAAO,IAAI,MAAM;IAC/B,OAAO,OAAO,iBAAiB,IAAI,OAAO,OAAO,SAAS,IAAI,CAAC;GACjE,CAAC;EACH;CACF,GAAG;EAAC;EAAc;EAAsB;CAAM,CAAC;CAE/C,OAAO;AACT"} | ||
| {"version":3,"file":"Transitioner.cjs","names":[],"sources":["../../src/Transitioner.tsx"],"sourcesContent":["'use client'\n\nimport * as React from 'react'\nimport { getLocationChangeInfo, trimPathRight } from '@tanstack/router-core'\nimport { useLayoutEffect } from './utils'\nimport { useRouter } from './useRouter'\nimport type { AnyRouteMatch } from '@tanstack/router-core'\n\nexport function Transitioner() {\n const router = useRouter()\n const acknowledgement = React.useRef<\n [Array<AnyRouteMatch>, (rendered: boolean) => void] | undefined\n >(undefined)\n const mounted =\n process.env.NODE_ENV !== 'production'\n ? // eslint-disable-next-line react-hooks/rules-of-hooks\n React.useRef(false)\n : undefined\n\n // `<Transitioner>` precedes `<MatchesInner>`, so install the render\n // acknowledgement before the latter can publish a rendered lane.\n router._rendered = (matches) => {\n const current = acknowledgement.current\n if (\n current?.[0].length === matches.length &&\n current[0].every(\n (match, index) =>\n match.id === matches[index]!.id &&\n match.abortController === matches[index]!.abortController &&\n match.status === matches[index]!.status,\n )\n ) {\n acknowledgement.current = undefined\n current[1](true)\n }\n }\n if (process.env.NODE_ENV === 'production') {\n router.startTransition = (fn, expected, urgent) =>\n new Promise((resolve) => {\n acknowledgement.current?.[1](false)\n acknowledgement.current = [expected, resolve]\n if (urgent) {\n fn()\n } else {\n React.startTransition(fn)\n }\n })\n } else {\n router.startTransition = (fn, expected, urgent) =>\n new Promise((resolve, reject) => {\n acknowledgement.current?.[1](false)\n const next: NonNullable<typeof acknowledgement.current> = [\n expected,\n resolve,\n ]\n acknowledgement.current = next\n try {\n if (urgent) {\n fn()\n } else {\n React.startTransition(fn)\n }\n } catch (cause) {\n if (acknowledgement.current === next) {\n acknowledgement.current = undefined\n }\n reject(cause)\n }\n })\n ;(\n router as typeof router & { _cancelTransition?: () => void }\n )._cancelTransition = () => {\n const current = acknowledgement.current\n acknowledgement.current = undefined\n current?.[1](false)\n }\n }\n\n // Subscribe before canonicalizing so the initial URL has exactly one load.\n useLayoutEffect(() => {\n const unsub = router.history.subscribe(router.load)\n\n if (mounted?.current) {\n return unsub\n }\n if (mounted) {\n mounted.current = true\n }\n\n router.updateLatestLocation()\n const location = router.latestLocation\n const nextLocation = router.buildLocation({\n to: location.pathname,\n search: true,\n params: true,\n hash: true,\n state: true,\n _includeValidateSearch: true,\n })\n\n // Check if the current URL matches the canonical form.\n // Compare publicHref (browser-facing URL) consistently with server\n // canonicalization.\n if (\n trimPathRight(location.publicHref) !==\n trimPathRight(nextLocation.publicHref)\n ) {\n router.commitLocation({\n ...nextLocation,\n replace: true,\n ignoreBlocker: true,\n })\n return unsub\n }\n\n const resolvedLocation = router.stores.resolvedLocation.get()\n if (\n resolvedLocation?.href === location.href &&\n resolvedLocation.state.__TSR_key === location.state.__TSR_key\n ) {\n acknowledgement.current = [\n router.stores.matches.get(),\n (rendered) => {\n if (rendered) {\n router.emit({\n type: 'onRendered',\n ...getLocationChangeInfo(resolvedLocation, resolvedLocation),\n })\n }\n },\n ]\n } else if (!router._tx) {\n router.load().catch(console.error)\n }\n\n return unsub\n // `mounted` exists only in development and is a stable ref when present.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [router, router.history])\n\n return null\n}\n"],"mappings":";;;;;;;;AAQA,SAAgB,eAAe;CAC7B,MAAM,SAAS,kBAAA,UAAU;CACzB,MAAM,kBAAkB,MAAM,OAE5B,KAAA,CAAS;CACX,MAAM,UAAA,QAAA,IAAA,aACqB,eAErB,MAAM,OAAO,KAAK,IAClB,KAAA;CAIN,OAAO,aAAa,YAAY;EAC9B,MAAM,UAAU,gBAAgB;EAChC,IACE,UAAU,GAAG,WAAW,QAAQ,UAChC,QAAQ,GAAG,OACR,OAAO,UACN,MAAM,OAAO,QAAQ,OAAQ,MAC7B,MAAM,oBAAoB,QAAQ,OAAQ,mBAC1C,MAAM,WAAW,QAAQ,OAAQ,MACrC,GACA;GACA,gBAAgB,UAAU,KAAA;GAC1B,QAAQ,GAAG,IAAI;EACjB;CACF;CACA,IAAA,QAAA,IAAA,aAA6B,cAC3B,OAAO,mBAAmB,IAAI,UAAU,WACtC,IAAI,SAAS,YAAY;EACvB,gBAAgB,UAAU,GAAG,KAAK;EAClC,gBAAgB,UAAU,CAAC,UAAU,OAAO;EAC5C,IAAI,QACF,GAAG;OAEH,MAAM,gBAAgB,EAAE;CAE5B,CAAC;MACE;EACL,OAAO,mBAAmB,IAAI,UAAU,WACtC,IAAI,SAAS,SAAS,WAAW;GAC/B,gBAAgB,UAAU,GAAG,KAAK;GAClC,MAAM,OAAoD,CACxD,UACA,OACF;GACA,gBAAgB,UAAU;GAC1B,IAAI;IACF,IAAI,QACF,GAAG;SAEH,MAAM,gBAAgB,EAAE;GAE5B,SAAS,OAAO;IACd,IAAI,gBAAgB,YAAY,MAC9B,gBAAgB,UAAU,KAAA;IAE5B,OAAO,KAAK;GACd;EACF,CAAC;EACF,OAEC,0BAA0B;GAC1B,MAAM,UAAU,gBAAgB;GAChC,gBAAgB,UAAU,KAAA;GAC1B,UAAU,GAAG,KAAK;EACpB;CACF;CAGA,cAAA,sBAAsB;EACpB,MAAM,QAAQ,OAAO,QAAQ,UAAU,OAAO,IAAI;EAElD,IAAI,SAAS,SACX,OAAO;EAET,IAAI,SACF,QAAQ,UAAU;EAGpB,OAAO,qBAAqB;EAC5B,MAAM,WAAW,OAAO;EACxB,MAAM,eAAe,OAAO,cAAc;GACxC,IAAI,SAAS;GACb,QAAQ;GACR,QAAQ;GACR,MAAM;GACN,OAAO;GACP,wBAAwB;EAC1B,CAAC;EAKD,KAAA,GAAA,sBAAA,eACgB,SAAS,UAAU,OAAA,GAAA,sBAAA,eACnB,aAAa,UAAU,GACrC;GACA,OAAO,eAAe;IACpB,GAAG;IACH,SAAS;IACT,eAAe;GACjB,CAAC;GACD,OAAO;EACT;EAEA,MAAM,mBAAmB,OAAO,OAAO,iBAAiB,IAAI;EAC5D,IACE,kBAAkB,SAAS,SAAS,QACpC,iBAAiB,MAAM,cAAc,SAAS,MAAM,WAEpD,gBAAgB,UAAU,CACxB,OAAO,OAAO,QAAQ,IAAI,IACzB,aAAa;GACZ,IAAI,UACF,OAAO,KAAK;IACV,MAAM;IACN,IAAA,GAAA,sBAAA,uBAAyB,kBAAkB,gBAAgB;GAC7D,CAAC;EAEL,CACF;OACK,IAAI,CAAC,OAAO,KACjB,OAAO,KAAK,EAAE,MAAM,QAAQ,KAAK;EAGnC,OAAO;CAGT,GAAG,CAAC,QAAQ,OAAO,OAAO,CAAC;CAE3B,OAAO;AACT"} |
| const require_useRouter = require("./useRouter.cjs"); | ||
| let _tanstack_router_core_isServer = require("@tanstack/router-core/isServer"); | ||
| let _tanstack_react_store = require("@tanstack/react-store"); | ||
| let _tanstack_router_core_isServer = require("@tanstack/router-core/isServer"); | ||
| //#region src/useCanGoBack.ts | ||
@@ -5,0 +5,0 @@ function useCanGoBack() { |
| "use client"; | ||
| const require_useRouter = require("./useRouter.cjs"); | ||
| const require_useMatch = require("./useMatch.cjs"); | ||
| let _tanstack_router_core_isServer = require("@tanstack/router-core/isServer"); | ||
| let _tanstack_react_store = require("@tanstack/react-store"); | ||
| let _tanstack_router_core_isServer = require("@tanstack/router-core/isServer"); | ||
| //#region src/useLocation.tsx | ||
@@ -7,0 +7,0 @@ /** |
@@ -8,11 +8,6 @@ "use client"; | ||
| react = require_runtime.__toESM(react, 1); | ||
| let _tanstack_router_core_isServer = require("@tanstack/router-core/isServer"); | ||
| let _tanstack_react_store = require("@tanstack/react-store"); | ||
| let _tanstack_router_core_isServer = require("@tanstack/router-core/isServer"); | ||
| //#region src/useMatch.tsx | ||
| var dummyStore = { | ||
| get() {}, | ||
| subscribe() { | ||
| return { unsubscribe() {} }; | ||
| } | ||
| }; | ||
| var dummyMatch = {}; | ||
| function useStructuralSharing(opts, router) { | ||
@@ -32,6 +27,7 @@ const previousResult = react.useRef(); | ||
| const router = require_useRouter.useRouter(); | ||
| const nearestMatchId = react.useContext(opts.from ? require_matchContext.dummyMatchContext : require_matchContext.matchContext); | ||
| const matchStore = opts.from ? router.stores.getRouteMatchStore(opts.from) : router.stores.matchStores.get(nearestMatchId); | ||
| const nearestRouteId = react.useContext(opts.from ? require_matchContext.dummyMatchContext : require_matchContext.matchContext); | ||
| const routeId = opts.from ?? nearestRouteId; | ||
| const matchStore = router.stores.getMatchStore(routeId); | ||
| if (_tanstack_router_core_isServer.isServer ?? router.isServer) { | ||
| const match = matchStore?.get(); | ||
| const match = matchStore.get(); | ||
| if (!match) { | ||
@@ -47,4 +43,4 @@ if (opts.shouldThrow ?? true) { | ||
| const selector = useStructuralSharing(opts, router); | ||
| const matchSelection = (0, _tanstack_react_store.useStore)(matchStore ?? dummyStore, (match) => match ? selector(match) : dummyStore); | ||
| if (matchSelection !== dummyStore) return matchSelection; | ||
| const matchSelection = (0, _tanstack_react_store.useStore)(matchStore, (match) => match ? selector(match) : dummyMatch); | ||
| if (matchSelection !== dummyMatch) return matchSelection; | ||
| if (opts.shouldThrow ?? true) { | ||
@@ -51,0 +47,0 @@ 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!"}`); |
@@ -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() {},\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"} | ||
| {"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 dummyMatch = {}\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 nearestRouteId = React.useContext(\n opts.from ? dummyMatchContext : matchContext,\n )\n\n const routeId = opts.from ?? nearestRouteId\n const matchStore = router.stores.getMatchStore(routeId!)\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, (match) =>\n match ? selector(match as any) : dummyMatch,\n )\n\n if (matchSelection !== dummyMatch) {\n return matchSelection as any\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,CAAC;AAEpB,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,UAAU,KAAK,QAAQ;CAC7B,MAAM,aAAa,OAAO,OAAO,cAAc,OAAQ;CAEvD,IAAI,+BAAA,YAAY,OAAO,UAAU;EAC/B,MAAM,QAAQ,WAAW,IAAI;EAC7B,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,aAAa,UAC3C,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"} |
| "use client"; | ||
| const require_useRouter = require("./useRouter.cjs"); | ||
| const require_useMatch = require("./useMatch.cjs"); | ||
| let _tanstack_router_core_isServer = require("@tanstack/router-core/isServer"); | ||
| let _tanstack_react_store = require("@tanstack/react-store"); | ||
| let _tanstack_router_core_isServer = require("@tanstack/router-core/isServer"); | ||
| //#region src/useRouterState.tsx | ||
@@ -7,0 +7,0 @@ /** |
+2
-17
@@ -5,2 +5,3 @@ "use client"; | ||
| react = require_runtime.__toESM(react, 1); | ||
| let _tanstack_router_core_isServer = require("@tanstack/router-core/isServer"); | ||
| /** | ||
@@ -11,19 +12,4 @@ * React.use if available (React 19+), undefined otherwise. | ||
| var reactUse = react["use"]; | ||
| var useLayoutEffect = typeof window !== "undefined" ? react.useLayoutEffect : react.useEffect; | ||
| var useLayoutEffect = _tanstack_router_core_isServer.isServer ?? typeof window === "undefined" ? react.useEffect : react.useLayoutEffect; | ||
| /** | ||
| * Taken from https://www.developerway.com/posts/implementing-advanced-use-previous-hook#part3 | ||
| */ | ||
| function usePrevious(value) { | ||
| const ref = react.useRef({ | ||
| value, | ||
| prev: null | ||
| }); | ||
| const current = ref.current.value; | ||
| if (value !== current) ref.current = { | ||
| value, | ||
| prev: current | ||
| }; | ||
| return ref.current.prev; | ||
| } | ||
| /** | ||
| * React hook to wrap `IntersectionObserver`. | ||
@@ -93,4 +79,3 @@ * | ||
| exports.useLayoutEffect = useLayoutEffect; | ||
| exports.usePrevious = usePrevious; | ||
| //# sourceMappingURL=utils.cjs.map |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"utils.cjs","names":[],"sources":["../../src/utils.ts"],"sourcesContent":["'use client'\nimport * as React from 'react'\n\n// Safe version of React.use() that will not cause compilation errors against\n// React 18 with Webpack, which statically analyzes imports and fails when it\n// sees React.use referenced (since 'use' is not exported from React 18).\n// This uses a dynamic string lookup to avoid the static analysis.\n// eslint-disable-next-line prefer-const -- Must be `let` to prevent bundler constant-folding\nlet REACT_USE = 'use'\n\n/**\n * React.use if available (React 19+), undefined otherwise.\n * Use dynamic lookup to avoid Webpack compilation errors with React 18.\n */\nexport const reactUse:\n | (<T>(usable: Promise<T> | React.Context<T>) => T)\n | undefined = (React as any)[REACT_USE]\n\nexport function useStableCallback<T extends (...args: Array<any>) => any>(\n fn: T,\n): T {\n const fnRef = React.useRef(fn)\n fnRef.current = fn\n\n const ref = React.useRef((...args: Array<any>) => fnRef.current(...args))\n return ref.current as T\n}\n\nexport const useLayoutEffect =\n typeof window !== 'undefined' ? React.useLayoutEffect : React.useEffect\n\n/**\n * Taken from https://www.developerway.com/posts/implementing-advanced-use-previous-hook#part3\n */\nexport function usePrevious<T>(value: T): T | null {\n // initialise the ref with previous and current values\n const ref = React.useRef<{ value: T; prev: T | null }>({\n value: value,\n prev: null,\n })\n\n const current = ref.current.value\n\n // if the value passed into hook doesn't match what we store as \"current\"\n // move the \"current\" to the \"previous\"\n // and store the passed value as \"current\"\n if (value !== current) {\n ref.current = {\n value: value,\n prev: current,\n }\n }\n\n // return the previous value only\n return ref.current.prev\n}\n\n/**\n * React hook to wrap `IntersectionObserver`.\n *\n * This hook will create an `IntersectionObserver` and observe the ref passed to it.\n *\n * When the intersection changes, the callback will be called with the `IntersectionObserverEntry`.\n *\n * @param ref - The ref to observe\n * @param intersectionObserverOptions - The options to pass to the IntersectionObserver\n * @param options - The options to pass to the hook\n * @param callback - The callback to call when the intersection changes\n * @returns The IntersectionObserver instance\n * @example\n * ```tsx\n * const MyComponent = () => {\n * const ref = React.useRef<HTMLDivElement>(null)\n * useIntersectionObserver(\n * ref,\n * (entry) => { doSomething(entry) },\n * { rootMargin: '10px' },\n * { disabled: false }\n * )\n * return <div ref={ref} />\n * ```\n */\nexport function useIntersectionObserver<T extends Element>(\n ref: React.RefObject<T | null>,\n callback: (entry: IntersectionObserverEntry | undefined) => void,\n intersectionObserverOptions: IntersectionObserverInit = {},\n options: { disabled?: boolean } = {},\n) {\n React.useEffect(() => {\n if (\n !ref.current ||\n options.disabled ||\n typeof IntersectionObserver !== 'function'\n ) {\n return\n }\n\n const observer = new IntersectionObserver(([entry]) => {\n callback(entry)\n }, intersectionObserverOptions)\n\n observer.observe(ref.current)\n\n return () => {\n observer.disconnect()\n }\n }, [callback, intersectionObserverOptions, options.disabled, ref])\n}\n\n/**\n * React hook to take a `React.ForwardedRef` and returns a `ref` that can be used on a DOM element.\n *\n * @param ref - The forwarded ref\n * @returns The inner ref returned by `useRef`\n * @example\n * ```tsx\n * const MyComponent = React.forwardRef((props, ref) => {\n * const innerRef = useForwardedRef(ref)\n * return <div ref={innerRef} />\n * })\n * ```\n */\nexport function useForwardedRef<T>(ref?: React.ForwardedRef<T>) {\n const innerRef = React.useRef<T>(null)\n React.useImperativeHandle(ref, () => innerRef.current!, [])\n return innerRef\n}\n"],"mappings":";;;;;;;;AAcA,IAAa,WAEI,MAAc;AAY/B,IAAa,kBACX,OAAO,WAAW,cAAc,MAAM,kBAAkB,MAAM;;;;AAKhE,SAAgB,YAAe,OAAoB;CAEjD,MAAM,MAAM,MAAM,OAAqC;EAC9C;EACP,MAAM;CACR,CAAC;CAED,MAAM,UAAU,IAAI,QAAQ;CAK5B,IAAI,UAAU,SACZ,IAAI,UAAU;EACL;EACP,MAAM;CACR;CAIF,OAAO,IAAI,QAAQ;AACrB;;;;;;;;;;;;;;;;;;;;;;;;;;AA2BA,SAAgB,wBACd,KACA,UACA,8BAAwD,CAAC,GACzD,UAAkC,CAAC,GACnC;CACA,MAAM,gBAAgB;EACpB,IACE,CAAC,IAAI,WACL,QAAQ,YACR,OAAO,yBAAyB,YAEhC;EAGF,MAAM,WAAW,IAAI,sBAAsB,CAAC,WAAW;GACrD,SAAS,KAAK;EAChB,GAAG,2BAA2B;EAE9B,SAAS,QAAQ,IAAI,OAAO;EAE5B,aAAa;GACX,SAAS,WAAW;EACtB;CACF,GAAG;EAAC;EAAU;EAA6B,QAAQ;EAAU;CAAG,CAAC;AACnE;;;;;;;;;;;;;;AAeA,SAAgB,gBAAmB,KAA6B;CAC9D,MAAM,WAAW,MAAM,OAAU,IAAI;CACrC,MAAM,oBAAoB,WAAW,SAAS,SAAU,CAAC,CAAC;CAC1D,OAAO;AACT"} | ||
| {"version":3,"file":"utils.cjs","names":[],"sources":["../../src/utils.ts"],"sourcesContent":["'use client'\nimport * as React from 'react'\nimport { isServer } from '@tanstack/router-core/isServer'\n\n// Safe version of React.use() that will not cause compilation errors against\n// React 18 with Webpack, which statically analyzes imports and fails when it\n// sees React.use referenced (since 'use' is not exported from React 18).\n// This uses a dynamic string lookup to avoid the static analysis.\n// eslint-disable-next-line prefer-const -- Must be `let` to prevent bundler constant-folding\nlet REACT_USE = 'use'\n\n/**\n * React.use if available (React 19+), undefined otherwise.\n * Use dynamic lookup to avoid Webpack compilation errors with React 18.\n */\nexport const reactUse:\n | (<T>(usable: Promise<T> | React.Context<T>) => T)\n | undefined = (React as any)[REACT_USE]\n\nexport function useStableCallback<T extends (...args: Array<any>) => any>(\n fn: T,\n): T {\n const fnRef = React.useRef(fn)\n fnRef.current = fn\n\n const ref = React.useRef((...args: Array<any>) => fnRef.current(...args))\n return ref.current as T\n}\n\nexport const useLayoutEffect =\n (isServer ?? typeof window === 'undefined')\n ? React.useEffect\n : React.useLayoutEffect\n\n/**\n * Taken from https://www.developerway.com/posts/implementing-advanced-use-previous-hook#part3\n */\nexport function usePrevious<T>(value: T): T | null {\n // initialise the ref with previous and current values\n const ref = React.useRef<{ value: T; prev: T | null }>({\n value: value,\n prev: null,\n })\n\n const current = ref.current.value\n\n // if the value passed into hook doesn't match what we store as \"current\"\n // move the \"current\" to the \"previous\"\n // and store the passed value as \"current\"\n if (value !== current) {\n ref.current = {\n value: value,\n prev: current,\n }\n }\n\n // return the previous value only\n return ref.current.prev\n}\n\n/**\n * React hook to wrap `IntersectionObserver`.\n *\n * This hook will create an `IntersectionObserver` and observe the ref passed to it.\n *\n * When the intersection changes, the callback will be called with the `IntersectionObserverEntry`.\n *\n * @param ref - The ref to observe\n * @param intersectionObserverOptions - The options to pass to the IntersectionObserver\n * @param options - The options to pass to the hook\n * @param callback - The callback to call when the intersection changes\n * @returns The IntersectionObserver instance\n * @example\n * ```tsx\n * const MyComponent = () => {\n * const ref = React.useRef<HTMLDivElement>(null)\n * useIntersectionObserver(\n * ref,\n * (entry) => { doSomething(entry) },\n * { rootMargin: '10px' },\n * { disabled: false }\n * )\n * return <div ref={ref} />\n * ```\n */\nexport function useIntersectionObserver<T extends Element>(\n ref: React.RefObject<T | null>,\n callback: (entry: IntersectionObserverEntry | undefined) => void,\n intersectionObserverOptions: IntersectionObserverInit = {},\n options: { disabled?: boolean } = {},\n) {\n React.useEffect(() => {\n if (\n !ref.current ||\n options.disabled ||\n typeof IntersectionObserver !== 'function'\n ) {\n return\n }\n\n const observer = new IntersectionObserver(([entry]) => {\n callback(entry)\n }, intersectionObserverOptions)\n\n observer.observe(ref.current)\n\n return () => {\n observer.disconnect()\n }\n }, [callback, intersectionObserverOptions, options.disabled, ref])\n}\n\n/**\n * React hook to take a `React.ForwardedRef` and returns a `ref` that can be used on a DOM element.\n *\n * @param ref - The forwarded ref\n * @returns The inner ref returned by `useRef`\n * @example\n * ```tsx\n * const MyComponent = React.forwardRef((props, ref) => {\n * const innerRef = useForwardedRef(ref)\n * return <div ref={innerRef} />\n * })\n * ```\n */\nexport function useForwardedRef<T>(ref?: React.ForwardedRef<T>) {\n const innerRef = React.useRef<T>(null)\n React.useImperativeHandle(ref, () => innerRef.current!, [])\n return innerRef\n}\n"],"mappings":";;;;;;;;;AAeA,IAAa,WAEI,MAAc;AAY/B,IAAa,kBACV,+BAAA,YAAY,OAAO,WAAW,cAC3B,MAAM,YACN,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;AAqDZ,SAAgB,wBACd,KACA,UACA,8BAAwD,CAAC,GACzD,UAAkC,CAAC,GACnC;CACA,MAAM,gBAAgB;EACpB,IACE,CAAC,IAAI,WACL,QAAQ,YACR,OAAO,yBAAyB,YAEhC;EAGF,MAAM,WAAW,IAAI,sBAAsB,CAAC,WAAW;GACrD,SAAS,KAAK;EAChB,GAAG,2BAA2B;EAE9B,SAAS,QAAQ,IAAI,OAAO;EAE5B,aAAa;GACX,SAAS,WAAW;EACtB;CACF,GAAG;EAAC;EAAU;EAA6B,QAAQ;EAAU;CAAG,CAAC;AACnE;;;;;;;;;;;;;;AAeA,SAAgB,gBAAmB,KAA6B;CAC9D,MAAM,WAAW,MAAM,OAAU,IAAI;CACrC,MAAM,oBAAoB,WAAW,SAAS,SAAU,CAAC,CAAC;CAC1D,OAAO;AACT"} |
@@ -8,3 +8,3 @@ import * as React from 'react'; | ||
| export declare function useStableCallback<T extends (...args: Array<any>) => any>(fn: T): T; | ||
| export declare const useLayoutEffect: typeof React.useLayoutEffect; | ||
| export declare const useLayoutEffect: typeof React.useEffect; | ||
| /** | ||
@@ -11,0 +11,0 @@ * Taken from https://www.developerway.com/posts/implementing-advanced-use-previous-hook#part3 |
@@ -5,4 +5,4 @@ "use client"; | ||
| import * as React$1 from "react"; | ||
| import { isServer } from "@tanstack/router-core/isServer"; | ||
| import { jsx } from "react/jsx-runtime"; | ||
| import { isServer } from "@tanstack/router-core/isServer"; | ||
| //#region src/Asset.tsx | ||
@@ -9,0 +9,0 @@ var INLINE_CSS_HYDRATION_ATTR = "data-tsr-inline-css"; |
@@ -5,3 +5,3 @@ import { ErrorRouteComponent } from './route.js'; | ||
| export declare function CatchBoundary(props: { | ||
| getResetKey: () => number | string; | ||
| getResetKey: () => unknown; | ||
| children: React.ReactNode; | ||
@@ -8,0 +8,0 @@ errorComponent?: ErrorRouteComponent; |
@@ -6,14 +6,3 @@ "use client"; | ||
| function CatchBoundary(props) { | ||
| const errorComponent = props.errorComponent ?? ErrorComponent; | ||
| return /* @__PURE__ */ jsx(CatchBoundaryImpl, { | ||
| getResetKey: props.getResetKey, | ||
| onCatch: props.onCatch, | ||
| children: ({ error, reset }) => { | ||
| if (error) return React$1.createElement(errorComponent, { | ||
| error, | ||
| reset | ||
| }); | ||
| return props.children; | ||
| } | ||
| }); | ||
| return /* @__PURE__ */ jsx(CatchBoundaryImpl, { ...props }); | ||
| } | ||
@@ -24,2 +13,5 @@ var CatchBoundaryImpl = class extends React$1.Component { | ||
| this.state = { error: null }; | ||
| this.reset = () => { | ||
| this.setState({ error: null }); | ||
| }; | ||
| } | ||
@@ -37,15 +29,11 @@ static getDerivedStateFromProps(props, state) { | ||
| } | ||
| reset() { | ||
| this.setState({ error: null }); | ||
| } | ||
| componentDidCatch(error, errorInfo) { | ||
| if (this.props.onCatch) this.props.onCatch(error, errorInfo); | ||
| this.props.onCatch?.(error, errorInfo); | ||
| } | ||
| render() { | ||
| return this.props.children({ | ||
| error: this.state.error, | ||
| reset: () => { | ||
| this.reset(); | ||
| } | ||
| }); | ||
| const error = this.state.error; | ||
| return error ? React$1.createElement(this.props.errorComponent ?? ErrorComponent, { | ||
| error, | ||
| reset: this.reset | ||
| }) : this.props.children; | ||
| } | ||
@@ -52,0 +40,0 @@ }; |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"CatchBoundary.js","names":[],"sources":["../../src/CatchBoundary.tsx"],"sourcesContent":["'use client'\n\nimport * as React from 'react'\nimport type { ErrorRouteComponent } from './route'\nimport type { ErrorInfo } from 'react'\n\nexport function CatchBoundary(props: {\n getResetKey: () => number | string\n children: React.ReactNode\n errorComponent?: ErrorRouteComponent\n onCatch?: (error: Error, errorInfo: ErrorInfo) => void\n}) {\n const errorComponent = props.errorComponent ?? ErrorComponent\n\n return (\n <CatchBoundaryImpl\n getResetKey={props.getResetKey}\n onCatch={props.onCatch}\n children={({ error, reset }) => {\n if (error) {\n return React.createElement(errorComponent, {\n error,\n reset,\n })\n }\n\n return props.children\n }}\n />\n )\n}\n\nclass CatchBoundaryImpl extends React.Component<{\n getResetKey: () => number | string\n children: (props: {\n error: Error | null\n reset: () => void\n }) => React.ReactNode\n onCatch?: (error: Error, errorInfo: ErrorInfo) => void\n}> {\n state = { error: null } as { error: Error | null; resetKey?: string | number }\n\n static getDerivedStateFromProps(\n props: { getResetKey: () => string | number },\n state: { resetKey?: string | number; error: Error | null },\n ) {\n const resetKey = props.getResetKey()\n\n if (state.error && state.resetKey !== resetKey) {\n return { resetKey, error: null }\n }\n\n return { resetKey }\n }\n static getDerivedStateFromError(error: Error) {\n return { error }\n }\n reset() {\n this.setState({ error: null })\n }\n componentDidCatch(error: Error, errorInfo: ErrorInfo) {\n if (this.props.onCatch) {\n this.props.onCatch(error, errorInfo)\n }\n }\n render() {\n return this.props.children({\n error: this.state.error,\n reset: () => {\n this.reset()\n },\n })\n }\n}\n\nexport function ErrorComponent({ error }: { error: any }) {\n const [show, setShow] = React.useState(process.env.NODE_ENV !== 'production')\n\n return (\n <div style={{ padding: '.5rem', maxWidth: '100%' }}>\n <div style={{ display: 'flex', alignItems: 'center', gap: '.5rem' }}>\n <strong style={{ fontSize: '1rem' }}>Something went wrong!</strong>\n <button\n style={{\n appearance: 'none',\n fontSize: '.6em',\n border: '1px solid currentColor',\n padding: '.1rem .2rem',\n fontWeight: 'bold',\n borderRadius: '.25rem',\n }}\n onClick={() => setShow((d) => !d)}\n >\n {show ? 'Hide Error' : 'Show Error'}\n </button>\n </div>\n <div style={{ height: '.25rem' }} />\n {show ? (\n <div>\n <pre\n style={{\n fontSize: '.7em',\n border: '1px solid red',\n borderRadius: '.25rem',\n padding: '.3rem',\n color: 'red',\n overflow: 'auto',\n }}\n >\n {error.message ? <code>{error.message}</code> : null}\n </pre>\n </div>\n ) : null}\n </div>\n )\n}\n"],"mappings":";;;;AAMA,SAAgB,cAAc,OAK3B;CACD,MAAM,iBAAiB,MAAM,kBAAkB;CAE/C,OACE,oBAAC,mBAAD;EACE,aAAa,MAAM;EACnB,SAAS,MAAM;EACf,WAAW,EAAE,OAAO,YAAY;GAC9B,IAAI,OACF,OAAO,QAAM,cAAc,gBAAgB;IACzC;IACA;GACF,CAAC;GAGH,OAAO,MAAM;EACf;CACD,CAAA;AAEL;AAEA,IAAM,oBAAN,cAAgC,QAAM,UAOnC;;;eACO,EAAE,OAAO,KAAK;;CAEtB,OAAO,yBACL,OACA,OACA;EACA,MAAM,WAAW,MAAM,YAAY;EAEnC,IAAI,MAAM,SAAS,MAAM,aAAa,UACpC,OAAO;GAAE;GAAU,OAAO;EAAK;EAGjC,OAAO,EAAE,SAAS;CACpB;CACA,OAAO,yBAAyB,OAAc;EAC5C,OAAO,EAAE,MAAM;CACjB;CACA,QAAQ;EACN,KAAK,SAAS,EAAE,OAAO,KAAK,CAAC;CAC/B;CACA,kBAAkB,OAAc,WAAsB;EACpD,IAAI,KAAK,MAAM,SACb,KAAK,MAAM,QAAQ,OAAO,SAAS;CAEvC;CACA,SAAS;EACP,OAAO,KAAK,MAAM,SAAS;GACzB,OAAO,KAAK,MAAM;GAClB,aAAa;IACX,KAAK,MAAM;GACb;EACF,CAAC;CACH;AACF;AAEA,SAAgB,eAAe,EAAE,SAAyB;CACxD,MAAM,CAAC,MAAM,WAAW,QAAM,SAAA,QAAA,IAAA,aAAkC,YAAY;CAE5E,OACE,qBAAC,OAAD;EAAK,OAAO;GAAE,SAAS;GAAS,UAAU;EAAO;YAAjD;GACE,qBAAC,OAAD;IAAK,OAAO;KAAE,SAAS;KAAQ,YAAY;KAAU,KAAK;IAAQ;cAAlE,CACE,oBAAC,UAAD;KAAQ,OAAO,EAAE,UAAU,OAAO;eAAG;IAA6B,CAAA,GAClE,oBAAC,UAAD;KACE,OAAO;MACL,YAAY;MACZ,UAAU;MACV,QAAQ;MACR,SAAS;MACT,YAAY;MACZ,cAAc;KAChB;KACA,eAAe,SAAS,MAAM,CAAC,CAAC;eAE/B,OAAO,eAAe;IACjB,CAAA,CACL;;GACL,oBAAC,OAAD,EAAK,OAAO,EAAE,QAAQ,SAAS,EAAI,CAAA;GAClC,OACC,oBAAC,OAAD,EAAA,UACE,oBAAC,OAAD;IACE,OAAO;KACL,UAAU;KACV,QAAQ;KACR,cAAc;KACd,SAAS;KACT,OAAO;KACP,UAAU;IACZ;cAEC,MAAM,UAAU,oBAAC,QAAD,EAAA,UAAO,MAAM,QAAc,CAAA,IAAI;GAC7C,CAAA,EACF,CAAA,IACH;EACD;;AAET"} | ||
| {"version":3,"file":"CatchBoundary.js","names":[],"sources":["../../src/CatchBoundary.tsx"],"sourcesContent":["'use client'\n\nimport * as React from 'react'\nimport type { ErrorRouteComponent } from './route'\nimport type { ErrorInfo } from 'react'\n\nexport function CatchBoundary(props: {\n getResetKey: () => unknown\n children: React.ReactNode\n errorComponent?: ErrorRouteComponent\n onCatch?: (error: Error, errorInfo: ErrorInfo) => void\n}) {\n return <CatchBoundaryImpl {...props} />\n}\n\nclass CatchBoundaryImpl extends React.Component<{\n getResetKey: () => unknown\n children: React.ReactNode\n errorComponent?: ErrorRouteComponent\n onCatch?: (error: Error, errorInfo: ErrorInfo) => void\n}> {\n state = { error: null } as { error: Error | null; resetKey?: unknown }\n\n static getDerivedStateFromProps(\n props: { getResetKey: () => unknown },\n state: { resetKey?: unknown; error: Error | null },\n ) {\n const resetKey = props.getResetKey()\n\n if (state.error && state.resetKey !== resetKey) {\n return { resetKey, error: null }\n }\n\n return { resetKey }\n }\n static getDerivedStateFromError(error: Error) {\n return { error }\n }\n reset = () => {\n this.setState({ error: null })\n }\n componentDidCatch(error: Error, errorInfo: ErrorInfo) {\n this.props.onCatch?.(error, errorInfo)\n }\n render() {\n const error = this.state.error\n return error\n ? React.createElement(this.props.errorComponent ?? ErrorComponent, {\n error,\n reset: this.reset,\n })\n : this.props.children\n }\n}\n\nexport function ErrorComponent({ error }: { error: any }) {\n const [show, setShow] = React.useState(process.env.NODE_ENV !== 'production')\n\n return (\n <div style={{ padding: '.5rem', maxWidth: '100%' }}>\n <div style={{ display: 'flex', alignItems: 'center', gap: '.5rem' }}>\n <strong style={{ fontSize: '1rem' }}>Something went wrong!</strong>\n <button\n style={{\n appearance: 'none',\n fontSize: '.6em',\n border: '1px solid currentColor',\n padding: '.1rem .2rem',\n fontWeight: 'bold',\n borderRadius: '.25rem',\n }}\n onClick={() => setShow((d) => !d)}\n >\n {show ? 'Hide Error' : 'Show Error'}\n </button>\n </div>\n <div style={{ height: '.25rem' }} />\n {show ? (\n <div>\n <pre\n style={{\n fontSize: '.7em',\n border: '1px solid red',\n borderRadius: '.25rem',\n padding: '.3rem',\n color: 'red',\n overflow: 'auto',\n }}\n >\n {error.message ? <code>{error.message}</code> : null}\n </pre>\n </div>\n ) : null}\n </div>\n )\n}\n"],"mappings":";;;;AAMA,SAAgB,cAAc,OAK3B;CACD,OAAO,oBAAC,mBAAD,EAAmB,GAAI,MAAQ,CAAA;AACxC;AAEA,IAAM,oBAAN,cAAgC,QAAM,UAKnC;;;eACO,EAAE,OAAO,KAAK;qBAiBR;GACZ,KAAK,SAAS,EAAE,OAAO,KAAK,CAAC;EAC/B;;CAjBA,OAAO,yBACL,OACA,OACA;EACA,MAAM,WAAW,MAAM,YAAY;EAEnC,IAAI,MAAM,SAAS,MAAM,aAAa,UACpC,OAAO;GAAE;GAAU,OAAO;EAAK;EAGjC,OAAO,EAAE,SAAS;CACpB;CACA,OAAO,yBAAyB,OAAc;EAC5C,OAAO,EAAE,MAAM;CACjB;CAIA,kBAAkB,OAAc,WAAsB;EACpD,KAAK,MAAM,UAAU,OAAO,SAAS;CACvC;CACA,SAAS;EACP,MAAM,QAAQ,KAAK,MAAM;EACzB,OAAO,QACH,QAAM,cAAc,KAAK,MAAM,kBAAkB,gBAAgB;GAC/D;GACA,OAAO,KAAK;EACd,CAAC,IACD,KAAK,MAAM;CACjB;AACF;AAEA,SAAgB,eAAe,EAAE,SAAyB;CACxD,MAAM,CAAC,MAAM,WAAW,QAAM,SAAA,QAAA,IAAA,aAAkC,YAAY;CAE5E,OACE,qBAAC,OAAD;EAAK,OAAO;GAAE,SAAS;GAAS,UAAU;EAAO;YAAjD;GACE,qBAAC,OAAD;IAAK,OAAO;KAAE,SAAS;KAAQ,YAAY;KAAU,KAAK;IAAQ;cAAlE,CACE,oBAAC,UAAD;KAAQ,OAAO,EAAE,UAAU,OAAO;eAAG;IAA6B,CAAA,GAClE,oBAAC,UAAD;KACE,OAAO;MACL,YAAY;MACZ,UAAU;MACV,QAAQ;MACR,SAAS;MACT,YAAY;MACZ,cAAc;KAChB;KACA,eAAe,SAAS,MAAM,CAAC,CAAC;eAE/B,OAAO,eAAe;IACjB,CAAA,CACL;;GACL,oBAAC,OAAD,EAAK,OAAO,EAAE,QAAQ,SAAS,EAAI,CAAA;GAClC,OACC,oBAAC,OAAD,EAAA,UACE,oBAAC,OAAD;IACE,OAAO;KACL,UAAU;KACV,QAAQ;KACR,cAAc;KACd,SAAS;KACT,OAAO;KACP,UAAU;IACZ;cAEC,MAAM,UAAU,oBAAC,QAAD,EAAA,UAAO,MAAM,QAAc,CAAA,IAAI;GAC7C,CAAA,EACF,CAAA,IACH;EACD;;AAET"} |
@@ -23,3 +23,3 @@ "use client"; | ||
| function ClientOnly({ children, fallback = null }) { | ||
| return useHydrated() ? /* @__PURE__ */ jsx(React.Fragment, { children }) : /* @__PURE__ */ jsx(React.Fragment, { children: fallback }); | ||
| return /* @__PURE__ */ jsx(React.Fragment, { children: useHydrated() ? children : fallback }); | ||
| } | ||
@@ -26,0 +26,0 @@ /** |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"ClientOnly.js","names":[],"sources":["../../src/ClientOnly.tsx"],"sourcesContent":["'use client'\n\nimport React from 'react'\n\nexport interface ClientOnlyProps {\n /**\n * The children to render when the JS is loaded.\n */\n children: React.ReactNode\n /**\n * The fallback component to render if the JS is not yet loaded.\n */\n fallback?: React.ReactNode\n}\n\n/**\n * Render the children only after the JS has loaded client-side. Use an optional\n * fallback component if the JS is not yet loaded.\n *\n * @example\n * Render a Chart component if JS loads, renders a simple FakeChart\n * component server-side or if there is no JS. The FakeChart can have only the\n * UI without the behavior or be a loading spinner or skeleton.\n *\n * ```tsx\n * return (\n * <ClientOnly fallback={<FakeChart />}>\n * <Chart />\n * </ClientOnly>\n * )\n * ```\n */\nexport function ClientOnly({ children, fallback = null }: ClientOnlyProps) {\n return useHydrated() ? (\n <React.Fragment>{children}</React.Fragment>\n ) : (\n <React.Fragment>{fallback}</React.Fragment>\n )\n}\n\n/**\n * Return a boolean indicating if the JS has been hydrated already.\n * When doing Server-Side Rendering, the result will always be false.\n * When doing Client-Side Rendering, the result will always be false on the\n * first render and true from then on. Even if a new component renders it will\n * always start with true.\n *\n * @example\n * ```tsx\n * // Disable a button that needs JS to work.\n * let hydrated = useHydrated()\n * return (\n * <button type=\"button\" disabled={!hydrated} onClick={doSomethingCustom}>\n * Click me\n * </button>\n * )\n * ```\n * @returns True if the JS has been hydrated already, false otherwise.\n */\nexport function useHydrated(): boolean {\n return React.useSyncExternalStore(\n subscribe,\n () => true,\n () => false,\n )\n}\n\nfunction subscribe() {\n return () => {\n // noop\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AAgCA,SAAgB,WAAW,EAAE,UAAU,WAAW,QAAyB;CACzE,OAAO,YAAY,IACjB,oBAAC,MAAM,UAAP,EAAiB,SAAyB,CAAA,IAE1C,oBAAC,MAAM,UAAP,EAAA,UAAiB,SAAyB,CAAA;AAE9C;;;;;;;;;;;;;;;;;;;;AAqBA,SAAgB,cAAuB;CACrC,OAAO,MAAM,qBACX,iBACM,YACA,KACR;AACF;AAEA,SAAS,YAAY;CACnB,aAAa,CAEb;AACF"} | ||
| {"version":3,"file":"ClientOnly.js","names":[],"sources":["../../src/ClientOnly.tsx"],"sourcesContent":["'use client'\n\nimport React from 'react'\n\nexport interface ClientOnlyProps {\n /**\n * The children to render when the JS is loaded.\n */\n children: React.ReactNode\n /**\n * The fallback component to render if the JS is not yet loaded.\n */\n fallback?: React.ReactNode\n}\n\n/**\n * Render the children only after the JS has loaded client-side. Use an optional\n * fallback component if the JS is not yet loaded.\n *\n * @example\n * Render a Chart component if JS loads, renders a simple FakeChart\n * component server-side or if there is no JS. The FakeChart can have only the\n * UI without the behavior or be a loading spinner or skeleton.\n *\n * ```tsx\n * return (\n * <ClientOnly fallback={<FakeChart />}>\n * <Chart />\n * </ClientOnly>\n * )\n * ```\n */\nexport function ClientOnly({ children, fallback = null }: ClientOnlyProps) {\n return <React.Fragment>{useHydrated() ? children : fallback}</React.Fragment>\n}\n\n/**\n * Return a boolean indicating if the JS has been hydrated already.\n * When doing Server-Side Rendering, the result will always be false.\n * When doing Client-Side Rendering, the result will always be false on the\n * first render and true from then on. Even if a new component renders it will\n * always start with true.\n *\n * @example\n * ```tsx\n * // Disable a button that needs JS to work.\n * let hydrated = useHydrated()\n * return (\n * <button type=\"button\" disabled={!hydrated} onClick={doSomethingCustom}>\n * Click me\n * </button>\n * )\n * ```\n * @returns True if the JS has been hydrated already, false otherwise.\n */\nexport function useHydrated(): boolean {\n return React.useSyncExternalStore(\n subscribe,\n () => true,\n () => false,\n )\n}\n\nfunction subscribe() {\n return () => {\n // noop\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AAgCA,SAAgB,WAAW,EAAE,UAAU,WAAW,QAAyB;CACzE,OAAO,oBAAC,MAAM,UAAP,EAAA,UAAiB,YAAY,IAAI,WAAW,SAAyB,CAAA;AAC9E;;;;;;;;;;;;;;;;;;;;AAqBA,SAAgB,cAAuB;CACrC,OAAO,MAAM,qBACX,iBACM,YACA,KACR;AACF;AAEA,SAAS,YAAY;CACnB,aAAa,CAEb;AACF"} |
| import { AssetCrossOriginConfig, RouterManagedTag } from '@tanstack/router-core'; | ||
| /** | ||
| * Build the list of head/link/meta/script tags to render for active matches. | ||
| * Build the head/link/meta/script tags from the renderable presented prefix. | ||
| * Used internally by `HeadContent`. | ||
| */ | ||
| export declare const useTags: (assetCrossOrigin?: AssetCrossOriginConfig) => RouterManagedTag[]; |
+10
-137
| import { useRouter } from "./useRouter.js"; | ||
| import { appendUniqueUserTags, deepEqual, escapeHtml, getAssetCrossOrigin, getScriptPreloadAttrs, resolveManifestCssLink } from "@tanstack/router-core"; | ||
| import { _getAssetMatches, appendUniqueUserTags, deepEqual, escapeHtml, getAssetCrossOrigin, getScriptPreloadAttrs, resolveManifestCssLink } from "@tanstack/router-core"; | ||
| import * as React$1 from "react"; | ||
| import { isServer } from "@tanstack/router-core/isServer"; | ||
| import { useStore } from "@tanstack/react-store"; | ||
| import { isServer } from "@tanstack/router-core/isServer"; | ||
| //#region src/headContentUtils.tsx | ||
| function buildTagsFromMatches(router, nonce, matches, assetCrossOrigin) { | ||
| matches = _getAssetMatches(matches); | ||
| const routeMeta = matches.map((match) => match.meta).filter((meta) => meta !== void 0); | ||
@@ -126,3 +127,3 @@ const resultMeta = []; | ||
| /** | ||
| * Build the list of head/link/meta/script tags to render for active matches. | ||
| * Build the head/link/meta/script tags from the renderable presented prefix. | ||
| * Used internally by `HeadContent`. | ||
@@ -134,136 +135,8 @@ */ | ||
| if (isServer ?? router.isServer) return buildTagsFromMatches(router, nonce, router.stores.matches.get(), assetCrossOrigin); | ||
| const routeMeta = useStore(router.stores.matches, (matches) => { | ||
| return matches.map((match) => match.meta).filter((meta) => meta !== void 0); | ||
| }, deepEqual); | ||
| const meta = React$1.useMemo(() => { | ||
| const resultMeta = []; | ||
| const metaByAttribute = {}; | ||
| let title; | ||
| for (let i = routeMeta.length - 1; i >= 0; i--) { | ||
| const metas = routeMeta[i]; | ||
| for (let j = metas.length - 1; j >= 0; j--) { | ||
| const m = metas[j]; | ||
| if (!m) continue; | ||
| if (m.title) { | ||
| if (!title) title = { | ||
| tag: "title", | ||
| children: m.title | ||
| }; | ||
| } else if ("script:ld+json" in m) try { | ||
| const json = JSON.stringify(m["script:ld+json"]); | ||
| resultMeta.push({ | ||
| tag: "script", | ||
| attrs: { type: "application/ld+json" }, | ||
| children: escapeHtml(json) | ||
| }); | ||
| } catch {} | ||
| else { | ||
| const attribute = m.name ?? m.property; | ||
| if (attribute) if (metaByAttribute[attribute]) continue; | ||
| else metaByAttribute[attribute] = true; | ||
| resultMeta.push({ | ||
| tag: "meta", | ||
| attrs: { | ||
| ...m, | ||
| nonce | ||
| } | ||
| }); | ||
| } | ||
| } | ||
| } | ||
| if (title) resultMeta.push(title); | ||
| if (nonce) resultMeta.push({ | ||
| tag: "meta", | ||
| attrs: { | ||
| property: "csp-nonce", | ||
| content: nonce | ||
| } | ||
| }); | ||
| resultMeta.reverse(); | ||
| return resultMeta; | ||
| }, [routeMeta, nonce]); | ||
| const links = useStore(router.stores.matches, (matches) => { | ||
| return matches.flatMap((match) => match.links ?? []).filter((link) => link !== void 0).map((link) => ({ | ||
| tag: "link", | ||
| attrs: { | ||
| ...link, | ||
| nonce | ||
| } | ||
| })); | ||
| }, deepEqual); | ||
| const manifestCssTags = useStore(router.stores.matches, (matches) => { | ||
| const manifest = router.ssr?.manifest; | ||
| const tags = []; | ||
| if (!manifest) return tags; | ||
| matches.forEach((match) => { | ||
| manifest.routes[match.routeId]?.css?.forEach((link) => { | ||
| const resolvedLink = resolveManifestCssLink(link); | ||
| tags.push({ | ||
| tag: "link", | ||
| attrs: { | ||
| rel: "stylesheet", | ||
| ...resolvedLink, | ||
| crossOrigin: getAssetCrossOrigin(assetCrossOrigin, "stylesheet") ?? resolvedLink.crossOrigin, | ||
| suppressHydrationWarning: true, | ||
| nonce | ||
| } | ||
| }); | ||
| }); | ||
| }); | ||
| if (manifest.inlineStyle) tags.push({ | ||
| tag: "style", | ||
| attrs: { | ||
| ...manifest.inlineStyle.attrs, | ||
| nonce | ||
| }, | ||
| children: manifest.inlineStyle.children, | ||
| inlineCss: true | ||
| }); | ||
| return tags; | ||
| }, deepEqual); | ||
| const preloadLinks = useStore(router.stores.matches, (matches) => { | ||
| const preloadLinks = []; | ||
| const manifest = router.ssr?.manifest; | ||
| if (!manifest) return preloadLinks; | ||
| matches.forEach((match) => { | ||
| manifest.routes[match.routeId]?.preloads?.forEach((preload) => { | ||
| preloadLinks.push({ | ||
| tag: "link", | ||
| attrs: { | ||
| ...getScriptPreloadAttrs(manifest, preload, assetCrossOrigin), | ||
| nonce | ||
| } | ||
| }); | ||
| }); | ||
| }); | ||
| return preloadLinks; | ||
| }, deepEqual); | ||
| const styles = useStore(router.stores.matches, (matches) => { | ||
| return matches.flatMap((match) => match.styles ?? []).filter((style) => style !== void 0).map(({ children, ...attrs }) => ({ | ||
| tag: "style", | ||
| attrs: { | ||
| ...attrs, | ||
| nonce | ||
| }, | ||
| children | ||
| })); | ||
| }, deepEqual); | ||
| const headScripts = useStore(router.stores.matches, (matches) => { | ||
| return matches.flatMap((match) => match.headScripts ?? []).filter((script) => script !== void 0).map(({ children, ...script }) => ({ | ||
| tag: "script", | ||
| attrs: { | ||
| ...script, | ||
| nonce | ||
| }, | ||
| children | ||
| })); | ||
| }, deepEqual); | ||
| const tags = []; | ||
| appendUniqueUserTags(tags, meta); | ||
| tags.push(...preloadLinks); | ||
| appendUniqueUserTags(tags, links); | ||
| tags.push(...manifestCssTags); | ||
| appendUniqueUserTags(tags, styles); | ||
| appendUniqueUserTags(tags, headScripts); | ||
| return tags; | ||
| const selectTags = React$1.useCallback((matches) => buildTagsFromMatches(router, nonce, matches, assetCrossOrigin), [ | ||
| assetCrossOrigin, | ||
| nonce, | ||
| router | ||
| ]); | ||
| return useStore(router.stores.matches, selectTags, deepEqual); | ||
| }; | ||
@@ -270,0 +143,0 @@ //#endregion |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"headContentUtils.js","names":[],"sources":["../../src/headContentUtils.tsx"],"sourcesContent":["import * as React from 'react'\nimport { useStore } from '@tanstack/react-store'\nimport {\n appendUniqueUserTags,\n deepEqual,\n escapeHtml,\n getAssetCrossOrigin,\n getScriptPreloadAttrs,\n resolveManifestCssLink,\n} from '@tanstack/router-core'\nimport { isServer } from '@tanstack/router-core/isServer'\nimport { useRouter } from './useRouter'\nimport type {\n AnyRouteMatch,\n AssetCrossOriginConfig,\n RouterManagedTag,\n} from '@tanstack/router-core'\n\nfunction buildTagsFromMatches(\n router: ReturnType<typeof useRouter>,\n nonce: string | undefined,\n matches: Array<AnyRouteMatch>,\n assetCrossOrigin?: AssetCrossOriginConfig,\n): Array<RouterManagedTag> {\n const routeMeta = matches\n .map((match) => match.meta)\n .filter((meta) => meta !== undefined)\n\n const resultMeta: Array<RouterManagedTag> = []\n const metaByAttribute: Record<string, true> = {}\n let title: RouterManagedTag | undefined\n for (let i = routeMeta.length - 1; i >= 0; i--) {\n const metas = routeMeta[i]!\n for (let j = metas.length - 1; j >= 0; j--) {\n const m = metas[j]\n if (!m) continue\n\n if (m.title) {\n if (!title) {\n title = {\n tag: 'title',\n children: m.title,\n }\n }\n } else if ('script:ld+json' in m) {\n try {\n const json = JSON.stringify(m['script:ld+json'])\n resultMeta.push({\n tag: 'script',\n attrs: {\n type: 'application/ld+json',\n },\n children: escapeHtml(json),\n })\n } catch {\n // Skip invalid JSON-LD objects\n }\n } else {\n const attribute = m.name ?? m.property\n if (attribute) {\n if (metaByAttribute[attribute]) {\n continue\n } else {\n metaByAttribute[attribute] = true\n }\n }\n\n resultMeta.push({\n tag: 'meta',\n attrs: {\n ...m,\n nonce,\n },\n })\n }\n }\n }\n\n if (title) {\n resultMeta.push(title)\n }\n\n if (nonce) {\n resultMeta.push({\n tag: 'meta',\n attrs: {\n property: 'csp-nonce',\n content: nonce,\n },\n })\n }\n resultMeta.reverse()\n\n const constructedLinks = matches\n .flatMap((match) => match.links ?? [])\n .filter((link) => link !== undefined)\n .map((link) => ({\n tag: 'link',\n attrs: {\n ...link,\n nonce,\n },\n })) satisfies Array<RouterManagedTag>\n\n const manifest = router.ssr?.manifest\n const manifestCssTags: Array<RouterManagedTag> = []\n if (manifest) {\n matches.forEach((match) => {\n const css = manifest.routes[match.routeId]?.css\n css?.forEach((link) => {\n const resolvedLink = resolveManifestCssLink(link)\n manifestCssTags.push({\n tag: 'link',\n attrs: {\n rel: 'stylesheet',\n ...resolvedLink,\n crossOrigin:\n getAssetCrossOrigin(assetCrossOrigin, 'stylesheet') ??\n resolvedLink.crossOrigin,\n suppressHydrationWarning: true,\n nonce,\n },\n })\n })\n })\n\n if (manifest.inlineStyle) {\n manifestCssTags.push({\n tag: 'style',\n attrs: {\n ...manifest.inlineStyle.attrs,\n nonce,\n },\n children: manifest.inlineStyle.children,\n inlineCss: true,\n })\n }\n }\n\n const preloadLinks: Array<RouterManagedTag> = []\n if (manifest) {\n matches.forEach((match) => {\n manifest.routes[match.routeId]?.preloads?.forEach((preload) => {\n preloadLinks.push({\n tag: 'link',\n attrs: {\n ...getScriptPreloadAttrs(manifest, preload, assetCrossOrigin),\n nonce,\n },\n })\n })\n })\n }\n\n const styles = matches\n .flatMap((match) => match.styles ?? [])\n .filter((style) => style !== undefined)\n .map(({ children, ...attrs }) => ({\n tag: 'style',\n attrs: {\n ...attrs,\n nonce,\n },\n children: children as string | undefined,\n })) satisfies Array<RouterManagedTag>\n\n const headScripts = matches\n .flatMap((match) => match.headScripts ?? [])\n .filter((script) => script !== undefined)\n .map(({ children, ...script }) => ({\n tag: 'script',\n attrs: {\n ...script,\n nonce,\n },\n children: children as string | undefined,\n })) satisfies Array<RouterManagedTag>\n\n const tags: Array<RouterManagedTag> = []\n appendUniqueUserTags(tags, resultMeta)\n tags.push(...preloadLinks)\n appendUniqueUserTags(tags, constructedLinks)\n tags.push(...manifestCssTags)\n appendUniqueUserTags(tags, styles)\n appendUniqueUserTags(tags, headScripts)\n return tags\n}\n\n/**\n * Build the list of head/link/meta/script tags to render for active matches.\n * Used internally by `HeadContent`.\n */\nexport const useTags = (assetCrossOrigin?: AssetCrossOriginConfig) => {\n const router = useRouter()\n const nonce = router.options.ssr?.nonce\n\n if (isServer ?? router.isServer) {\n return buildTagsFromMatches(\n router,\n nonce,\n router.stores.matches.get(),\n assetCrossOrigin,\n )\n }\n\n // eslint-disable-next-line react-hooks/rules-of-hooks -- condition is static\n const routeMeta = useStore(\n router.stores.matches,\n (matches) => {\n return matches\n .map((match) => match.meta)\n .filter((meta) => meta !== undefined)\n },\n deepEqual,\n )\n\n // eslint-disable-next-line react-hooks/rules-of-hooks -- condition is static\n const meta: Array<RouterManagedTag> = React.useMemo(() => {\n const resultMeta: Array<RouterManagedTag> = []\n const metaByAttribute: Record<string, true> = {}\n let title: RouterManagedTag | undefined\n for (let i = routeMeta.length - 1; i >= 0; i--) {\n const metas = routeMeta[i]!\n for (let j = metas.length - 1; j >= 0; j--) {\n const m = metas[j]\n if (!m) continue\n\n if (m.title) {\n if (!title) {\n title = {\n tag: 'title',\n children: m.title,\n }\n }\n } else if ('script:ld+json' in m) {\n // Handle JSON-LD structured data\n // Content is HTML-escaped to prevent XSS when injected via dangerouslySetInnerHTML\n try {\n const json = JSON.stringify(m['script:ld+json'])\n resultMeta.push({\n tag: 'script',\n attrs: {\n type: 'application/ld+json',\n },\n children: escapeHtml(json),\n })\n } catch {\n // Skip invalid JSON-LD objects\n }\n } else {\n const attribute = m.name ?? m.property\n if (attribute) {\n if (metaByAttribute[attribute]) {\n continue\n } else {\n metaByAttribute[attribute] = true\n }\n }\n\n resultMeta.push({\n tag: 'meta',\n attrs: {\n ...m,\n nonce,\n },\n })\n }\n }\n }\n\n if (title) {\n resultMeta.push(title)\n }\n\n if (nonce) {\n resultMeta.push({\n tag: 'meta',\n attrs: {\n property: 'csp-nonce',\n content: nonce,\n },\n })\n }\n resultMeta.reverse()\n\n return resultMeta\n }, [routeMeta, nonce])\n\n // eslint-disable-next-line react-hooks/rules-of-hooks -- condition is static\n const links = useStore(\n router.stores.matches,\n (matches) => {\n const constructed = matches\n .flatMap((match) => match.links ?? [])\n .filter((link) => link !== undefined)\n .map((link) => ({\n tag: 'link',\n attrs: {\n ...link,\n nonce,\n },\n })) satisfies Array<RouterManagedTag>\n\n return constructed\n },\n deepEqual,\n )\n\n // eslint-disable-next-line react-hooks/rules-of-hooks -- condition is static\n const manifestCssTags = useStore(\n router.stores.matches,\n (matches) => {\n const manifest = router.ssr?.manifest\n const tags: Array<RouterManagedTag> = []\n\n if (!manifest) {\n return tags\n }\n\n matches.forEach((match) => {\n manifest.routes[match.routeId]?.css?.forEach((link) => {\n const resolvedLink = resolveManifestCssLink(link)\n tags.push({\n tag: 'link',\n attrs: {\n rel: 'stylesheet',\n ...resolvedLink,\n crossOrigin:\n getAssetCrossOrigin(assetCrossOrigin, 'stylesheet') ??\n resolvedLink.crossOrigin,\n suppressHydrationWarning: true,\n nonce,\n },\n })\n })\n })\n\n if (manifest.inlineStyle) {\n tags.push({\n tag: 'style',\n attrs: {\n ...manifest.inlineStyle.attrs,\n nonce,\n },\n children: manifest.inlineStyle.children,\n inlineCss: true,\n })\n }\n\n return tags\n },\n deepEqual,\n )\n\n // eslint-disable-next-line react-hooks/rules-of-hooks -- condition is static\n const preloadLinks = useStore(\n router.stores.matches,\n (matches) => {\n const preloadLinks: Array<RouterManagedTag> = []\n const manifest = router.ssr?.manifest\n\n if (!manifest) {\n return preloadLinks\n }\n\n matches.forEach((match) => {\n manifest.routes[match.routeId]?.preloads?.forEach((preload) => {\n preloadLinks.push({\n tag: 'link',\n attrs: {\n ...getScriptPreloadAttrs(manifest, preload, assetCrossOrigin),\n nonce,\n },\n })\n })\n })\n\n return preloadLinks\n },\n deepEqual,\n )\n\n // eslint-disable-next-line react-hooks/rules-of-hooks -- condition is static\n const styles = useStore(\n router.stores.matches,\n (matches) => {\n return matches\n .flatMap((match) => match.styles ?? [])\n .filter((style) => style !== undefined)\n .map(({ children, ...attrs }) => ({\n tag: 'style',\n attrs: {\n ...attrs,\n nonce,\n },\n children: children as string | undefined,\n })) satisfies Array<RouterManagedTag>\n },\n deepEqual,\n )\n\n // eslint-disable-next-line react-hooks/rules-of-hooks -- condition is static\n const headScripts: Array<RouterManagedTag> = useStore(\n router.stores.matches,\n (matches) => {\n return matches\n .flatMap((match) => match.headScripts ?? [])\n .filter((script) => script !== undefined)\n .map(({ children, ...script }) => ({\n tag: 'script',\n attrs: {\n ...script,\n nonce,\n },\n children: children as string | undefined,\n })) satisfies Array<RouterManagedTag>\n },\n deepEqual,\n )\n\n const tags: Array<RouterManagedTag> = []\n appendUniqueUserTags(tags, meta)\n tags.push(...preloadLinks)\n appendUniqueUserTags(tags, links)\n tags.push(...manifestCssTags)\n appendUniqueUserTags(tags, styles)\n appendUniqueUserTags(tags, headScripts)\n return tags\n}\n"],"mappings":"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"} | ||
| {"version":3,"file":"headContentUtils.js","names":[],"sources":["../../src/headContentUtils.tsx"],"sourcesContent":["import * as React from 'react'\nimport { useStore } from '@tanstack/react-store'\nimport {\n _getAssetMatches,\n appendUniqueUserTags,\n deepEqual,\n escapeHtml,\n getAssetCrossOrigin,\n getScriptPreloadAttrs,\n resolveManifestCssLink,\n} from '@tanstack/router-core'\nimport { isServer } from '@tanstack/router-core/isServer'\nimport { useRouter } from './useRouter'\nimport type {\n AnyRouteMatch,\n AssetCrossOriginConfig,\n RouterManagedTag,\n} from '@tanstack/router-core'\n\nfunction buildTagsFromMatches(\n router: ReturnType<typeof useRouter>,\n nonce: string | undefined,\n matches: Array<AnyRouteMatch>,\n assetCrossOrigin?: AssetCrossOriginConfig,\n): Array<RouterManagedTag> {\n matches = _getAssetMatches(matches)\n const routeMeta = matches\n .map((match) => match.meta)\n .filter((meta) => meta !== undefined)\n\n const resultMeta: Array<RouterManagedTag> = []\n const metaByAttribute: Record<string, true> = {}\n let title: RouterManagedTag | undefined\n for (let i = routeMeta.length - 1; i >= 0; i--) {\n const metas = routeMeta[i]!\n for (let j = metas.length - 1; j >= 0; j--) {\n const m = metas[j]\n if (!m) continue\n\n if (m.title) {\n if (!title) {\n title = {\n tag: 'title',\n children: m.title,\n }\n }\n } else if ('script:ld+json' in m) {\n try {\n const json = JSON.stringify(m['script:ld+json'])\n resultMeta.push({\n tag: 'script',\n attrs: {\n type: 'application/ld+json',\n },\n children: escapeHtml(json),\n })\n } catch {\n // Skip invalid JSON-LD objects\n }\n } else {\n const attribute = m.name ?? m.property\n if (attribute) {\n if (metaByAttribute[attribute]) {\n continue\n } else {\n metaByAttribute[attribute] = true\n }\n }\n\n resultMeta.push({\n tag: 'meta',\n attrs: {\n ...m,\n nonce,\n },\n })\n }\n }\n }\n\n if (title) {\n resultMeta.push(title)\n }\n\n if (nonce) {\n resultMeta.push({\n tag: 'meta',\n attrs: {\n property: 'csp-nonce',\n content: nonce,\n },\n })\n }\n resultMeta.reverse()\n\n const constructedLinks = matches\n .flatMap((match) => match.links ?? [])\n .filter((link) => link !== undefined)\n .map((link) => ({\n tag: 'link',\n attrs: {\n ...link,\n nonce,\n },\n })) satisfies Array<RouterManagedTag>\n\n const manifest = router.ssr?.manifest\n const manifestCssTags: Array<RouterManagedTag> = []\n if (manifest) {\n matches.forEach((match) => {\n const css = manifest.routes[match.routeId]?.css\n css?.forEach((link) => {\n const resolvedLink = resolveManifestCssLink(link)\n manifestCssTags.push({\n tag: 'link',\n attrs: {\n rel: 'stylesheet',\n ...resolvedLink,\n crossOrigin:\n getAssetCrossOrigin(assetCrossOrigin, 'stylesheet') ??\n resolvedLink.crossOrigin,\n suppressHydrationWarning: true,\n nonce,\n },\n })\n })\n })\n\n if (manifest.inlineStyle) {\n manifestCssTags.push({\n tag: 'style',\n attrs: {\n ...manifest.inlineStyle.attrs,\n nonce,\n },\n children: manifest.inlineStyle.children,\n inlineCss: true,\n })\n }\n }\n\n const preloadLinks: Array<RouterManagedTag> = []\n if (manifest) {\n matches.forEach((match) => {\n manifest.routes[match.routeId]?.preloads?.forEach((preload) => {\n preloadLinks.push({\n tag: 'link',\n attrs: {\n ...getScriptPreloadAttrs(manifest, preload, assetCrossOrigin),\n nonce,\n },\n })\n })\n })\n }\n\n const styles = matches\n .flatMap((match) => match.styles ?? [])\n .filter((style) => style !== undefined)\n .map(({ children, ...attrs }) => ({\n tag: 'style',\n attrs: {\n ...attrs,\n nonce,\n },\n children: children as string | undefined,\n })) satisfies Array<RouterManagedTag>\n\n const headScripts = matches\n .flatMap((match) => match.headScripts ?? [])\n .filter((script) => script !== undefined)\n .map(({ children, ...script }) => ({\n tag: 'script',\n attrs: {\n ...script,\n nonce,\n },\n children: children as string | undefined,\n })) satisfies Array<RouterManagedTag>\n\n const tags: Array<RouterManagedTag> = []\n appendUniqueUserTags(tags, resultMeta)\n tags.push(...preloadLinks)\n appendUniqueUserTags(tags, constructedLinks)\n tags.push(...manifestCssTags)\n appendUniqueUserTags(tags, styles)\n appendUniqueUserTags(tags, headScripts)\n return tags\n}\n\n/**\n * Build the head/link/meta/script tags from the renderable presented prefix.\n * Used internally by `HeadContent`.\n */\nexport const useTags = (assetCrossOrigin?: AssetCrossOriginConfig) => {\n const router = useRouter()\n const nonce = router.options.ssr?.nonce\n\n if (isServer ?? router.isServer) {\n return buildTagsFromMatches(\n router,\n nonce,\n router.stores.matches.get(),\n assetCrossOrigin,\n )\n }\n\n // eslint-disable-next-line react-hooks/rules-of-hooks -- condition is static\n const selectTags = React.useCallback(\n (matches: Array<AnyRouteMatch>) =>\n buildTagsFromMatches(router, nonce, matches, assetCrossOrigin),\n [assetCrossOrigin, nonce, router],\n )\n // eslint-disable-next-line react-hooks/rules-of-hooks -- condition is static\n return useStore(router.stores.matches, selectTags, deepEqual)\n}\n"],"mappings":"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"} |
| import { reactUse } from "./utils.js"; | ||
| import { isModuleNotFoundError } from "@tanstack/router-core"; | ||
| import * as React$1 from "react"; | ||
| import { isServer } from "@tanstack/router-core/isServer"; | ||
| //#region src/lazyRouteComponent.tsx | ||
@@ -18,27 +19,27 @@ /** | ||
| let error; | ||
| let reload; | ||
| const load = () => { | ||
| if (!loadPromise) loadPromise = importer().then((res) => { | ||
| loadPromise = void 0; | ||
| comp = res[exportName ?? "default"]; | ||
| }).catch((err) => { | ||
| error = err; | ||
| if (isModuleNotFoundError(error)) { | ||
| if (error instanceof Error && typeof window !== "undefined" && typeof sessionStorage !== "undefined") { | ||
| const storageKey = `tanstack_router_reload:${error.message}`; | ||
| if (!sessionStorage.getItem(storageKey)) { | ||
| sessionStorage.setItem(storageKey, "1"); | ||
| reload = true; | ||
| } | ||
| } | ||
| } | ||
| }); | ||
| if (!loadPromise) { | ||
| error = void 0; | ||
| loadPromise = importer().then((res) => { | ||
| if (!(isServer ?? typeof window === "undefined")) loadPromise = void 0; | ||
| comp = res[exportName ?? "default"]; | ||
| }).catch((err) => { | ||
| loadPromise = void 0; | ||
| error = err; | ||
| }); | ||
| } | ||
| return loadPromise; | ||
| }; | ||
| const lazyComp = function Lazy(props) { | ||
| if (reload) { | ||
| window.location.reload(); | ||
| throw new Promise(() => {}); | ||
| if (error) { | ||
| if (isModuleNotFoundError(error) && !(isServer ?? typeof window === "undefined") && typeof sessionStorage !== "undefined") { | ||
| const storageKey = `tanstack_router_reload:${error.message}`; | ||
| if (!sessionStorage.getItem(storageKey)) { | ||
| sessionStorage.setItem(storageKey, "1"); | ||
| window.location.reload(); | ||
| throw new Promise(() => {}); | ||
| } | ||
| } | ||
| throw error; | ||
| } | ||
| if (error) throw error; | ||
| if (!comp) if (reactUse) reactUse(load()); | ||
@@ -45,0 +46,0 @@ else throw load(); |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"lazyRouteComponent.js","names":[],"sources":["../../src/lazyRouteComponent.tsx"],"sourcesContent":["import * as React from 'react'\nimport { isModuleNotFoundError } from '@tanstack/router-core'\nimport { reactUse } from './utils'\nimport type { AsyncRouteComponent } from './route'\n\n/**\n * Wrap a dynamic import to create a route component that supports\n * `.preload()` and friendly reload-on-module-missing behavior.\n *\n * @param importer Function returning a module promise\n * @param exportName Named export to use (default: `default`)\n * @returns A lazy route component compatible with TanStack Router\n * @link https://tanstack.com/router/latest/docs/framework/react/api/router/lazyRouteComponentFunction\n */\nexport function lazyRouteComponent<\n T extends Record<string, any>,\n TKey extends keyof T = 'default',\n>(\n importer: () => Promise<T>,\n exportName?: TKey,\n): T[TKey] extends (props: infer TProps) => any\n ? AsyncRouteComponent<TProps>\n : never {\n let loadPromise: Promise<any> | undefined\n let comp: T[TKey] | T['default']\n let error: any\n let reload: boolean\n\n const load = () => {\n if (!loadPromise) {\n loadPromise = importer()\n .then((res) => {\n loadPromise = undefined\n comp = res[exportName ?? 'default']\n })\n .catch((err) => {\n // We don't want an error thrown from preload in this case, because\n // there's nothing we want to do about module not found during preload.\n // Record the error, the rest is handled during the render path.\n error = err\n // If the load fails due to module not found, it may mean a new version of\n // the build was deployed and the user's browser is still using an old version.\n // If this happens, the old version in the user's browser would have an outdated\n // URL to the lazy module.\n // In that case, we want to attempt one window refresh to get the latest.\n if (isModuleNotFoundError(error)) {\n if (\n error instanceof Error &&\n typeof window !== 'undefined' &&\n typeof sessionStorage !== 'undefined'\n ) {\n // Again, we want to reload one time on module not found error and not enter\n // a reload loop if there is some other issue besides an old deploy.\n // That's why we store our reload attempt in sessionStorage.\n // Use error.message as key because it contains the module path that failed.\n const storageKey = `tanstack_router_reload:${error.message}`\n if (!sessionStorage.getItem(storageKey)) {\n sessionStorage.setItem(storageKey, '1')\n reload = true\n }\n }\n }\n })\n }\n\n return loadPromise\n }\n\n const lazyComp = function Lazy(props: any) {\n // Now that we're out of preload and into actual render path,\n if (reload) {\n // If it was a module loading error,\n // throw eternal suspense while we wait for window to reload\n window.location.reload()\n throw new Promise(() => {})\n }\n if (error) {\n // Otherwise, just throw the error\n throw error\n }\n\n if (!comp) {\n if (reactUse) {\n reactUse(load())\n } else {\n throw load()\n }\n }\n\n return React.createElement(comp, props)\n }\n\n ;(lazyComp as any).preload = load\n\n return lazyComp as any\n}\n"],"mappings":";;;;;;;;;;;;;AAcA,SAAgB,mBAId,UACA,YAGQ;CACR,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CAEJ,MAAM,aAAa;EACjB,IAAI,CAAC,aACH,cAAc,SAAS,EACpB,MAAM,QAAQ;GACb,cAAc,KAAA;GACd,OAAO,IAAI,cAAc;EAC3B,CAAC,EACA,OAAO,QAAQ;GAId,QAAQ;GAMR,IAAI,sBAAsB,KAAK;QAE3B,iBAAiB,SACjB,OAAO,WAAW,eAClB,OAAO,mBAAmB,aAC1B;KAKA,MAAM,aAAa,0BAA0B,MAAM;KACnD,IAAI,CAAC,eAAe,QAAQ,UAAU,GAAG;MACvC,eAAe,QAAQ,YAAY,GAAG;MACtC,SAAS;KACX;IACF;;EAEJ,CAAC;EAGL,OAAO;CACT;CAEA,MAAM,WAAW,SAAS,KAAK,OAAY;EAEzC,IAAI,QAAQ;GAGV,OAAO,SAAS,OAAO;GACvB,MAAM,IAAI,cAAc,CAAC,CAAC;EAC5B;EACA,IAAI,OAEF,MAAM;EAGR,IAAI,CAAC,MACH,IAAI,UACF,SAAS,KAAK,CAAC;OAEf,MAAM,KAAK;EAIf,OAAO,QAAM,cAAc,MAAM,KAAK;CACxC;CAEC,SAAkB,UAAU;CAE7B,OAAO;AACT"} | ||
| {"version":3,"file":"lazyRouteComponent.js","names":[],"sources":["../../src/lazyRouteComponent.tsx"],"sourcesContent":["import * as React from 'react'\nimport { isModuleNotFoundError } from '@tanstack/router-core'\nimport { isServer } from '@tanstack/router-core/isServer'\nimport { reactUse } from './utils'\nimport type { AsyncRouteComponent } from './route'\n\n/**\n * Wrap a dynamic import to create a route component that supports\n * `.preload()` and friendly reload-on-module-missing behavior.\n *\n * @param importer Function returning a module promise\n * @param exportName Named export to use (default: `default`)\n * @returns A lazy route component compatible with TanStack Router\n * @link https://tanstack.com/router/latest/docs/framework/react/api/router/lazyRouteComponentFunction\n */\nexport function lazyRouteComponent<\n T extends Record<string, any>,\n TKey extends keyof T = 'default',\n>(\n importer: () => Promise<T>,\n exportName?: TKey,\n): T[TKey] extends (props: infer TProps) => any\n ? AsyncRouteComponent<TProps>\n : never {\n let loadPromise: Promise<any> | undefined\n let comp: T[TKey] | T['default']\n let error: any\n\n const load = () => {\n if (!loadPromise) {\n error = undefined\n loadPromise = importer()\n .then((res) => {\n // Keep browser preload behavior unchanged; SSR can reuse the import.\n if (!(isServer ?? typeof window === 'undefined')) {\n loadPromise = undefined\n }\n comp = res[exportName ?? 'default']\n })\n .catch((err) => {\n loadPromise = undefined\n // We don't want an error thrown from preload in this case, because\n // there's nothing we want to do about module not found during preload.\n // Record the error, the rest is handled during the render path.\n error = err\n })\n }\n\n return loadPromise\n }\n\n const lazyComp = function Lazy(props: any) {\n if (error) {\n // A missing module can mean that a newer deployment replaced the URL.\n // Reload only for the error that is still current at render time, so a\n // successful retry cannot leave a stale reload request armed.\n if (\n isModuleNotFoundError(error) &&\n !(isServer ?? typeof window === 'undefined') &&\n typeof sessionStorage !== 'undefined'\n ) {\n const storageKey = `tanstack_router_reload:${error.message}`\n if (!sessionStorage.getItem(storageKey)) {\n sessionStorage.setItem(storageKey, '1')\n window.location.reload()\n // Suspend forever while the document reloads.\n throw new Promise(() => {})\n }\n }\n throw error\n }\n\n if (!comp) {\n if (reactUse) {\n reactUse(load())\n } else {\n throw load()\n }\n }\n\n return React.createElement(comp, props)\n }\n\n ;(lazyComp as any).preload = load\n\n return lazyComp as any\n}\n"],"mappings":";;;;;;;;;;;;;;AAeA,SAAgB,mBAId,UACA,YAGQ;CACR,IAAI;CACJ,IAAI;CACJ,IAAI;CAEJ,MAAM,aAAa;EACjB,IAAI,CAAC,aAAa;GAChB,QAAQ,KAAA;GACR,cAAc,SAAS,EACpB,MAAM,QAAQ;IAEb,IAAI,EAAE,YAAY,OAAO,WAAW,cAClC,cAAc,KAAA;IAEhB,OAAO,IAAI,cAAc;GAC3B,CAAC,EACA,OAAO,QAAQ;IACd,cAAc,KAAA;IAId,QAAQ;GACV,CAAC;EACL;EAEA,OAAO;CACT;CAEA,MAAM,WAAW,SAAS,KAAK,OAAY;EACzC,IAAI,OAAO;GAIT,IACE,sBAAsB,KAAK,KAC3B,EAAE,YAAY,OAAO,WAAW,gBAChC,OAAO,mBAAmB,aAC1B;IACA,MAAM,aAAa,0BAA0B,MAAM;IACnD,IAAI,CAAC,eAAe,QAAQ,UAAU,GAAG;KACvC,eAAe,QAAQ,YAAY,GAAG;KACtC,OAAO,SAAS,OAAO;KAEvB,MAAM,IAAI,cAAc,CAAC,CAAC;IAC5B;GACF;GACA,MAAM;EACR;EAEA,IAAI,CAAC,MACH,IAAI,UACF,SAAS,KAAK,CAAC;OAEf,MAAM,KAAK;EAIf,OAAO,QAAM,cAAc,MAAM,KAAK;CACxC;CAEC,SAAkB,UAAU;CAE7B,OAAO;AACT"} |
+1
-1
@@ -7,5 +7,5 @@ "use client"; | ||
| import * as React$1 from "react"; | ||
| import { isServer } from "@tanstack/router-core/isServer"; | ||
| import { jsx } from "react/jsx-runtime"; | ||
| import { useStore } from "@tanstack/react-store"; | ||
| import { isServer } from "@tanstack/router-core/isServer"; | ||
| import { flushSync } from "react-dom"; | ||
@@ -12,0 +12,0 @@ //#region src/link.tsx |
@@ -0,7 +1,10 @@ | ||
| import { useRouter } from './useRouter.js'; | ||
| import { AnyRoute, AnyRouteMatch } from '@tanstack/router-core'; | ||
| import * as React from 'react'; | ||
| export declare const Match: React.MemoExoticComponent<({ matchId, }: { | ||
| matchId: string; | ||
| export declare function renderPending(router: ReturnType<typeof useRouter>, route?: AnyRoute): import("react/jsx-runtime").JSX.Element | null; | ||
| export declare const Match: React.MemoExoticComponent<({ routeId, }: { | ||
| routeId: string; | ||
| }) => import("react/jsx-runtime").JSX.Element>; | ||
| export declare const MatchInner: React.MemoExoticComponent<({ matchId, }: { | ||
| matchId: string; | ||
| export declare const MatchInner: React.MemoExoticComponent<({ match, }: { | ||
| match: AnyRouteMatch; | ||
| }) => any>; | ||
@@ -8,0 +11,0 @@ /** |
+55
-195
| "use client"; | ||
| import { useLayoutEffect } from "./utils.js"; | ||
| import { CatchBoundary, ErrorComponent } from "./CatchBoundary.js"; | ||
@@ -11,84 +10,47 @@ import { ClientOnly } from "./ClientOnly.js"; | ||
| import { ScrollRestoration } from "./scroll-restoration.js"; | ||
| import { createControlledPromise, getLocationChangeInfo, invariant, isNotFound, isRedirect, rootRouteId } from "@tanstack/router-core"; | ||
| import { isNotFound, rootRouteId } from "@tanstack/router-core"; | ||
| import * as React$1 from "react"; | ||
| import { Fragment, jsx, jsxs } from "react/jsx-runtime"; | ||
| import { isServer } from "@tanstack/router-core/isServer"; | ||
| import { jsx, jsxs } from "react/jsx-runtime"; | ||
| import { useStore } from "@tanstack/react-store"; | ||
| import { isServer } from "@tanstack/router-core/isServer"; | ||
| //#region src/Match.tsx | ||
| var matchViewFieldsEqual = (a, b) => a.routeId === b.routeId && a._displayPending === b._displayPending; | ||
| function renderPending(router, route) { | ||
| const PendingComponent = route?.options.pendingComponent ?? router.options.defaultPendingComponent; | ||
| return PendingComponent ? /* @__PURE__ */ jsx(PendingComponent, {}) : null; | ||
| } | ||
| var outletMatchSelectionEqual = (a, b) => a[0] === b[0] && a[1] === b[1]; | ||
| var Match = React$1.memo(function MatchImpl({ matchId }) { | ||
| var Match = React$1.memo(function MatchImpl({ routeId }) { | ||
| const router = useRouter(); | ||
| if (isServer ?? router.isServer) { | ||
| const match = router.stores.matchStores.get(matchId)?.get(); | ||
| if (!match) { | ||
| if (process.env.NODE_ENV !== "production") throw new Error(`Invariant failed: Could not find match for matchId "${matchId}". Please file an issue!`); | ||
| invariant(); | ||
| } | ||
| const routeId = match.routeId; | ||
| const parentRouteId = router.routesById[routeId].parentRoute?.id; | ||
| return /* @__PURE__ */ jsx(MatchView, { | ||
| router, | ||
| matchId, | ||
| resetKey: router.stores.loadedAt.get(), | ||
| matchState: { | ||
| routeId, | ||
| ssr: match.ssr, | ||
| _displayPending: match._displayPending, | ||
| parentRouteId | ||
| } | ||
| }); | ||
| } | ||
| const matchStore = router.stores.matchStores.get(matchId); | ||
| if (!matchStore) { | ||
| if (process.env.NODE_ENV !== "production") throw new Error(`Invariant failed: Could not find match for matchId "${matchId}". Please file an issue!`); | ||
| invariant(); | ||
| } | ||
| const resetKey = useStore(router.stores.loadedAt, (loadedAt) => loadedAt); | ||
| const match = useStore(matchStore, (value) => value, matchViewFieldsEqual); | ||
| if (isServer ?? router.isServer) return /* @__PURE__ */ jsx(MatchView, { | ||
| router, | ||
| match: router.stores.byRoute.get(routeId).get() | ||
| }); | ||
| return /* @__PURE__ */ jsx(MatchView, { | ||
| router, | ||
| matchId, | ||
| resetKey, | ||
| matchState: React$1.useMemo(() => { | ||
| const routeId = match.routeId; | ||
| const parentRouteId = router.routesById[routeId].parentRoute?.id; | ||
| return { | ||
| routeId, | ||
| ssr: match.ssr, | ||
| _displayPending: match._displayPending, | ||
| parentRouteId | ||
| }; | ||
| }, [ | ||
| match._displayPending, | ||
| match.routeId, | ||
| match.ssr, | ||
| router.routesById | ||
| ]) | ||
| match: useStore(router.stores.getMatchStore(routeId), (value) => value) | ||
| }); | ||
| }); | ||
| function MatchView({ router, matchId, resetKey, matchState }) { | ||
| const route = router.routesById[matchState.routeId]; | ||
| const PendingComponent = route.options.pendingComponent ?? router.options.defaultPendingComponent; | ||
| const pendingElement = PendingComponent ? /* @__PURE__ */ jsx(PendingComponent, {}) : null; | ||
| function MatchView({ router, match }) { | ||
| const route = router.routesById[match.routeId]; | ||
| const pendingElement = renderPending(router, route); | ||
| const routeErrorComponent = route.options.errorComponent ?? router.options.defaultErrorComponent; | ||
| const routeOnCatch = route.options.onCatch ?? router.options.defaultOnCatch; | ||
| const routeNotFoundComponent = route.isRoot ? route.options.notFoundComponent ?? router.options.notFoundRoute?.options.component : route.options.notFoundComponent; | ||
| const resolvedNoSsr = matchState.ssr === false || matchState.ssr === "data-only"; | ||
| const ResolvedSuspenseBoundary = (!route.isRoot || route.options.wrapInSuspense || resolvedNoSsr) && (route.options.wrapInSuspense ?? PendingComponent ?? (route.options.errorComponent?.preload || resolvedNoSsr)) ? React$1.Suspense : SafeFragment; | ||
| const resolvedNoSsr = match.ssr === false || match.ssr === "data-only"; | ||
| const ResolvedSuspenseBoundary = route.options.wrapInSuspense ?? pendingElement ?? (route.options.errorComponent?.preload || resolvedNoSsr) ? React$1.Suspense : SafeFragment; | ||
| const ResolvedCatchBoundary = routeErrorComponent ? CatchBoundary : SafeFragment; | ||
| const ResolvedNotFoundBoundary = routeNotFoundComponent ? CatchNotFound : SafeFragment; | ||
| return /* @__PURE__ */ jsxs(route.isRoot ? route.options.shellComponent ?? SafeFragment : SafeFragment, { children: [/* @__PURE__ */ jsx(matchContext.Provider, { | ||
| value: matchId, | ||
| value: match.routeId, | ||
| children: /* @__PURE__ */ jsx(ResolvedSuspenseBoundary, { | ||
| fallback: pendingElement, | ||
| children: /* @__PURE__ */ jsx(ResolvedCatchBoundary, { | ||
| getResetKey: () => resetKey, | ||
| errorComponent: routeErrorComponent || ErrorComponent, | ||
| getResetKey: () => match, | ||
| errorComponent: routeErrorComponent, | ||
| onCatch: (error, errorInfo) => { | ||
| if (isNotFound(error)) { | ||
| error.routeId ??= matchState.routeId; | ||
| error.routeId ??= match.routeId; | ||
| throw error; | ||
| } | ||
| if (process.env.NODE_ENV !== "production") console.warn(`Warning: Error in route match: ${matchId}`); | ||
| if (process.env.NODE_ENV !== "production") console.warn(`Warning: Error in route match: ${match.id}`); | ||
| routeOnCatch?.(error, errorInfo); | ||
@@ -98,86 +60,21 @@ }, | ||
| fallback: (error) => { | ||
| error.routeId ??= matchState.routeId; | ||
| if (!routeNotFoundComponent || error.routeId && error.routeId !== matchState.routeId || !error.routeId && !route.isRoot) throw error; | ||
| error.routeId ??= match.routeId; | ||
| if (error.routeId !== match.routeId) throw error; | ||
| return React$1.createElement(routeNotFoundComponent, error); | ||
| }, | ||
| children: resolvedNoSsr || matchState._displayPending ? /* @__PURE__ */ jsx(ClientOnly, { | ||
| children: resolvedNoSsr ? /* @__PURE__ */ jsx(ClientOnly, { | ||
| fallback: pendingElement, | ||
| children: /* @__PURE__ */ jsx(MatchInner, { matchId }) | ||
| }) : /* @__PURE__ */ jsx(MatchInner, { matchId }) | ||
| children: /* @__PURE__ */ jsx(MatchInner, { match }) | ||
| }) : /* @__PURE__ */ jsx(MatchInner, { match }) | ||
| }) | ||
| }) | ||
| }) | ||
| }), matchState.parentRouteId === rootRouteId ? /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(OnRendered, {}), router.options.scrollRestoration && (isServer ?? router.isServer) ? /* @__PURE__ */ jsx(ScrollRestoration, {}) : null] }) : null] }); | ||
| }), (isServer ?? router.isServer) && route.parentRoute?.id === rootRouteId && router.options.scrollRestoration ? /* @__PURE__ */ jsx(ScrollRestoration, {}) : null] }); | ||
| } | ||
| function OnRendered() { | ||
| var MatchInner = React$1.memo(function MatchInnerImpl({ match }) { | ||
| const router = useRouter(); | ||
| if (isServer ?? router.isServer) return null; | ||
| const prevResolvedLocationRef = React$1.useRef(); | ||
| useLayoutEffect(() => { | ||
| 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; | ||
| } | ||
| var MatchInner = React$1.memo(function MatchInnerImpl({ matchId }) { | ||
| const router = useRouter(); | ||
| const getMatchPromise = (match, key) => { | ||
| return router.getMatch(match.id)?._nonReactive[key] ?? match._nonReactive[key]; | ||
| }; | ||
| if (isServer ?? router.isServer) { | ||
| const match = router.stores.matchStores.get(matchId)?.get(); | ||
| if (!match) { | ||
| if (process.env.NODE_ENV !== "production") throw new Error(`Invariant failed: Could not find match for matchId "${matchId}". Please file an issue!`); | ||
| invariant(); | ||
| } | ||
| const routeId = match.routeId; | ||
| const route = router.routesById[routeId]; | ||
| const remountDeps = (router.routesById[routeId].options.remountDeps ?? router.options.defaultRemountDeps)?.({ | ||
| routeId, | ||
| loaderDeps: match.loaderDeps, | ||
| params: match._strictParams, | ||
| search: match._strictSearch | ||
| }); | ||
| const key = remountDeps ? JSON.stringify(remountDeps) : void 0; | ||
| const Comp = route.options.component ?? router.options.defaultComponent; | ||
| const out = Comp ? /* @__PURE__ */ jsx(Comp, {}, key) : /* @__PURE__ */ jsx(Outlet, {}); | ||
| if (match._displayPending) throw getMatchPromise(match, "displayPendingPromise"); | ||
| if (match._forcePending) throw getMatchPromise(match, "minPendingPromise"); | ||
| if (match.status === "pending") throw getMatchPromise(match, "loadPromise"); | ||
| if (match.status === "notFound") { | ||
| if (!isNotFound(match.error)) { | ||
| if (process.env.NODE_ENV !== "production") throw new Error("Invariant failed: Expected a notFound error"); | ||
| invariant(); | ||
| } | ||
| return renderRouteNotFound(router, route, match.error); | ||
| } | ||
| if (match.status === "redirected") { | ||
| if (!isRedirect(match.error)) { | ||
| if (process.env.NODE_ENV !== "production") throw new Error("Invariant failed: Expected a redirect error"); | ||
| invariant(); | ||
| } | ||
| throw getMatchPromise(match, "loadPromise"); | ||
| } | ||
| if (match.status === "error") return /* @__PURE__ */ jsx((route.options.errorComponent ?? router.options.defaultErrorComponent) || ErrorComponent, { | ||
| error: match.error, | ||
| reset: void 0, | ||
| info: { componentStack: "" } | ||
| }); | ||
| return out; | ||
| } | ||
| const matchStore = router.stores.matchStores.get(matchId); | ||
| if (!matchStore) { | ||
| if (process.env.NODE_ENV !== "production") throw new Error(`Invariant failed: Could not find match for matchId "${matchId}". Please file an issue!`); | ||
| invariant(); | ||
| } | ||
| const match = useStore(matchStore, (value) => value); | ||
| const routeId = match.routeId; | ||
| const route = router.routesById[routeId]; | ||
| const key = React$1.useMemo(() => { | ||
| const remountDeps = (router.routesById[routeId].options.remountDeps ?? router.options.defaultRemountDeps)?.({ | ||
| const remountDeps = (route.options.remountDeps ?? router.options.defaultRemountDeps)?.({ | ||
| routeId, | ||
@@ -194,9 +91,8 @@ loaderDeps: match.loaderDeps, | ||
| match._strictSearch, | ||
| router.options.defaultRemountDeps, | ||
| router.routesById | ||
| route.options.remountDeps, | ||
| router.options.defaultRemountDeps | ||
| ]); | ||
| const out = React$1.useMemo(() => { | ||
| const Comp = route.options.component ?? router.options.defaultComponent; | ||
| if (Comp) return /* @__PURE__ */ jsx(Comp, {}, key); | ||
| return /* @__PURE__ */ jsx(Outlet, {}); | ||
| return Comp ? /* @__PURE__ */ jsx(Comp, {}, key) : /* @__PURE__ */ jsx(Outlet, {}); | ||
| }, [ | ||
@@ -207,35 +103,7 @@ key, | ||
| ]); | ||
| if (match._displayPending) throw getMatchPromise(match, "displayPendingPromise"); | ||
| if (match._forcePending) throw getMatchPromise(match, "minPendingPromise"); | ||
| if (match.status === "pending") { | ||
| const pendingMinMs = route.options.pendingMinMs ?? router.options.defaultPendingMinMs; | ||
| if (pendingMinMs) { | ||
| const routerMatch = router.getMatch(match.id); | ||
| if (routerMatch && !routerMatch._nonReactive.minPendingPromise) { | ||
| if (!(isServer ?? router.isServer)) { | ||
| const minPendingPromise = createControlledPromise(); | ||
| routerMatch._nonReactive.minPendingPromise = minPendingPromise; | ||
| setTimeout(() => { | ||
| minPendingPromise.resolve(); | ||
| routerMatch._nonReactive.minPendingPromise = void 0; | ||
| }, pendingMinMs); | ||
| } | ||
| } | ||
| } | ||
| throw getMatchPromise(match, "loadPromise"); | ||
| if (router._tx) throw router._tx[5]; | ||
| return renderPending(router, route); | ||
| } | ||
| if (match.status === "notFound") { | ||
| if (!isNotFound(match.error)) { | ||
| if (process.env.NODE_ENV !== "production") throw new Error("Invariant failed: Expected a notFound error"); | ||
| invariant(); | ||
| } | ||
| return renderRouteNotFound(router, route, match.error); | ||
| } | ||
| if (match.status === "redirected") { | ||
| if (!isRedirect(match.error)) { | ||
| if (process.env.NODE_ENV !== "production") throw new Error("Invariant failed: Expected a redirect error"); | ||
| invariant(); | ||
| } | ||
| throw getMatchPromise(match, "loadPromise"); | ||
| } | ||
| if (match.status === "notFound") return renderRouteNotFound(router, route, match.error); | ||
| if (match.status === "error") { | ||
@@ -259,33 +127,25 @@ if (isServer ?? router.isServer) return /* @__PURE__ */ jsx((route.options.errorComponent ?? router.options.defaultErrorComponent) || ErrorComponent, { | ||
| const router = useRouter(); | ||
| const matchId = React$1.useContext(matchContext); | ||
| let routeId; | ||
| let parentGlobalNotFound = false; | ||
| let childMatchId; | ||
| const routeId = React$1.useContext(matchContext); | ||
| let parentGlobalNotFound; | ||
| let parentNotFoundError; | ||
| let childRouteId; | ||
| if (isServer ?? router.isServer) { | ||
| const matches = router.stores.matches.get(); | ||
| const parentIndex = matchId ? matches.findIndex((match) => match.id === matchId) : -1; | ||
| const parentMatch = parentIndex >= 0 ? matches[parentIndex] : void 0; | ||
| routeId = parentMatch?.routeId; | ||
| parentGlobalNotFound = parentMatch?.globalNotFound ?? false; | ||
| childMatchId = parentIndex >= 0 ? matches[parentIndex + 1]?.id : void 0; | ||
| const parentIndex = matches.findIndex((match) => match.routeId === routeId); | ||
| const parentMatch = matches[parentIndex]; | ||
| parentGlobalNotFound = !!parentMatch._notFound; | ||
| parentNotFoundError = parentMatch.error; | ||
| childRouteId = matches[parentIndex + 1]?.routeId; | ||
| } else { | ||
| const parentMatchStore = matchId ? router.stores.matchStores.get(matchId) : void 0; | ||
| [routeId, parentGlobalNotFound] = useStore(parentMatchStore, (match) => [match?.routeId, match?.globalNotFound ?? false], outletMatchSelectionEqual); | ||
| childMatchId = useStore(router.stores.matchesId, (ids) => { | ||
| return ids[ids.findIndex((id) => id === matchId) + 1]; | ||
| const parentMatchStore = router.stores.getMatchStore(routeId); | ||
| [parentGlobalNotFound, parentNotFoundError] = useStore(parentMatchStore, (match) => [!!match._notFound, match.error], outletMatchSelectionEqual); | ||
| childRouteId = useStore(router.stores.ids, (ids) => { | ||
| return ids[ids.indexOf(routeId) + 1]; | ||
| }); | ||
| } | ||
| const route = routeId ? router.routesById[routeId] : void 0; | ||
| const pendingElement = router.options.defaultPendingComponent ? /* @__PURE__ */ jsx(router.options.defaultPendingComponent, {}) : null; | ||
| if (parentGlobalNotFound) { | ||
| if (!route) { | ||
| if (process.env.NODE_ENV !== "production") throw new Error("Invariant failed: Could not resolve route for Outlet render"); | ||
| invariant(); | ||
| } | ||
| return renderRouteNotFound(router, route, void 0); | ||
| } | ||
| if (!childMatchId) return null; | ||
| const nextMatch = /* @__PURE__ */ jsx(Match, { matchId: childMatchId }); | ||
| if (parentGlobalNotFound) return renderRouteNotFound(router, router.routesById[routeId], parentNotFoundError); | ||
| if (!childRouteId) return null; | ||
| const nextMatch = /* @__PURE__ */ jsx(Match, { routeId: childRouteId }); | ||
| if (routeId === rootRouteId) return /* @__PURE__ */ jsx(React$1.Suspense, { | ||
| fallback: pendingElement, | ||
| fallback: renderPending(router), | ||
| children: nextMatch | ||
@@ -296,4 +156,4 @@ }); | ||
| //#endregion | ||
| export { Match, Outlet }; | ||
| export { Match, Outlet, renderPending }; | ||
| //# sourceMappingURL=Match.js.map |
@@ -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 {\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":";;;;;;;;;;;;;;;;AAkCA,IAAM,wBAAwB,GAAkB,MAC9C,EAAE,YAAY,EAAE,WAAW,EAAE,oBAAoB,EAAE;AAErD,IAAM,6BACJ,GACA,MACG,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE;AAEjC,IAAa,QAAQ,QAAM,KAAK,SAAS,UAAU,EACjD,WAGC;CACD,MAAM,SAAS,UAAU;CAEzB,IAAI,YAAY,OAAO,UAAU;EAC/B,MAAM,QAAQ,OAAO,OAAO,YAAY,IAAI,OAAO,GAAG,IAAI;EAC1D,IAAI,CAAC,OAAO;GACV,IAAA,QAAA,IAAA,aAA6B,cAC3B,MAAM,IAAI,MACR,uDAAuD,QAAQ,yBACjE;GAGF,UAAU;EACZ;EAEA,MAAM,UAAU,MAAM;EACtB,MAAM,gBAAiB,OAAO,WAAW,SAAsB,aAC3D;EAEJ,OACE,oBAAC,WAAD;GACU;GACC;GACT,UAAU,OAAO,OAAO,SAAS,IAAI;GACrC,YAAY;IACV;IACA,KAAK,MAAM;IACX,iBAAiB,MAAM;IACvB;GACF;EACD,CAAA;CAEL;CAMA,MAAM,aAAa,OAAO,OAAO,YAAY,IAAI,OAAO;CACxD,IAAI,CAAC,YAAY;EACf,IAAA,QAAA,IAAA,aAA6B,cAC3B,MAAM,IAAI,MACR,uDAAuD,QAAQ,yBACjE;EAGF,UAAU;CACZ;CAEA,MAAM,WAAW,SAAS,OAAO,OAAO,WAAW,aAAa,QAAQ;CAExE,MAAM,QAAQ,SAAS,aAAa,UAAU,OAAO,oBAAoB;CAezE,OACE,oBAAC,WAAD;EACU;EACC;EACC;EACE,YAlBG,QAAM,cAAc;GACrC,MAAM,UAAU,MAAM;GACtB,MAAM,gBAAiB,OAAO,WAAW,SAAsB,aAC3D;GAEJ,OAAO;IACL;IACA,KAAK,MAAM;IACX,iBAAiB,MAAM;IACR;GACjB;EACF,GAAG;GAAC,MAAM;GAAiB,MAAM;GAAS,MAAM;GAAK,OAAO;EAAU,CAOtD;CACb,CAAA;AAEL,CAAC;AASD,SAAS,UAAU,EACjB,QACA,SACA,UACA,cAMC;CACD,MAAM,QAAkB,OAAO,WAAW,WAAW;CAErD,MAAM,mBACJ,MAAM,QAAQ,oBAAoB,OAAO,QAAQ;CAEnD,MAAM,iBAAiB,mBAAmB,oBAAC,kBAAD,CAAmB,CAAA,IAAI;CAEjE,MAAM,sBACJ,MAAM,QAAQ,kBAAkB,OAAO,QAAQ;CAEjD,MAAM,eAAe,MAAM,QAAQ,WAAW,OAAO,QAAQ;CAE7D,MAAM,yBAAyB,MAAM,SAEhC,MAAM,QAAQ,qBACf,OAAO,QAAQ,eAAe,QAAQ,YACtC,MAAM,QAAQ;CAElB,MAAM,gBACJ,WAAW,QAAQ,SAAS,WAAW,QAAQ;CACjD,MAAM,4BAEH,CAAC,MAAM,UAAU,MAAM,QAAQ,kBAAkB,mBACjD,MAAM,QAAQ,kBACb,qBACE,MAAM,QAAQ,gBAAwB,WAAW,kBACjD,QAAM,WACN;CAEN,MAAM,wBAAwB,sBAC1B,gBACA;CAEJ,MAAM,2BAA2B,yBAC7B,gBACA;CAKJ,OACE,qBAJqB,MAAM,SACvB,MAAM,QAA6B,kBAAkB,eACvD,cAEF,EAAA,UAAA,CACE,oBAAC,aAAa,UAAd;EAAuB,OAAO;YAC5B,oBAAC,0BAAD;GAA0B,UAAU;aAClC,oBAAC,uBAAD;IACE,mBAAmB;IACnB,gBAAgB,uBAAuB;IACvC,UAAU,OAAO,cAAc;KAE7B,IAAI,WAAW,KAAK,GAAG;MACrB,MAAM,YAAY,WAAW;MAC7B,MAAM;KACR;KACA,IAAA,QAAA,IAAA,aAA6B,cAC3B,QAAQ,KAAK,kCAAkC,SAAS;KAE1D,eAAe,OAAO,SAAS;IACjC;cAEA,oBAAC,0BAAD;KACE,WAAW,UAAU;MACnB,MAAM,YAAY,WAAW;MAI7B,IACE,CAAC,0BACA,MAAM,WAAW,MAAM,YAAY,WAAW,WAC9C,CAAC,MAAM,WAAW,CAAC,MAAM,QAE1B,MAAM;MAER,OAAO,QAAM,cAAc,wBAAwB,KAAY;KACjE;eAEC,iBAAiB,WAAW,kBAC3B,oBAAC,YAAD;MAAY,UAAU;gBACpB,oBAAC,YAAD,EAAqB,QAAU,CAAA;KACrB,CAAA,IAEZ,oBAAC,YAAD,EAAqB,QAAU,CAAA;IAET,CAAA;GACL,CAAA;EACC,CAAA;CACL,CAAA,GACtB,WAAW,kBAAkB,cAC5B,qBAAA,UAAA,EAAA,UAAA,CACE,oBAAC,YAAD,CAAa,CAAA,GACZ,OAAO,QAAQ,sBAAsB,YAAY,OAAO,YACvD,oBAAC,mBAAD,CAAoB,CAAA,IAClB,IACJ,EAAA,CAAA,IACA,IACU,EAAA,CAAA;AAEpB;AAMA,SAAS,aAAa;CACpB,MAAM,SAAS,UAAU;CAEzB,IAAI,YAAY,OAAO,UACrB,OAAO;CAUT,MAAM,0BAA0B,QAAM,OAEpC;CAQF,sBAAsB;EACpB,MAAM,0BAA0B,OAAO,OAAO,iBAAiB,IAAI;EACnE,MAAM,2BAA2B,wBAAwB;EAEzD,IACE,4BACC,CAAC,4BACA,yBAAyB,SAAS,wBAAwB,OAE5D,OAAO,KAAK;GACV,MAAM;GACN,GAAG,sBACD,OAAO,OAAO,SAAS,IAAI,GAC3B,4BAA4B,uBAC9B;EACF,CAAC;EAEH,wBAAwB,UAAU;CACpC,GAAG,CAxByB,SAC1B,OAAO,OAAO,mBACb,qBAAqB,kBAAkB,MAAM,SAsB5C,GAAqB,MAAM,CAAC;CAEhC,OAAO;AACT;AAEA,IAAa,aAAa,QAAM,KAAK,SAAS,eAAe,EAC3D,WAGM;CACN,MAAM,SAAS,UAAU;CAEzB,MAAM,mBACJ,OAQA,QACG;EACH,OACE,OAAO,SAAS,MAAM,EAAE,GAAG,aAAa,QAAQ,MAAM,aAAa;CAEvE;CAEA,IAAI,YAAY,OAAO,UAAU;EAC/B,MAAM,QAAQ,OAAO,OAAO,YAAY,IAAI,OAAO,GAAG,IAAI;EAC1D,IAAI,CAAC,OAAO;GACV,IAAA,QAAA,IAAA,aAA6B,cAC3B,MAAM,IAAI,MACR,uDAAuD,QAAQ,yBACjE;GAGF,UAAU;EACZ;EAEA,MAAM,UAAU,MAAM;EACtB,MAAM,QAAQ,OAAO,WAAW;EAIhC,MAAM,eAFH,OAAO,WAAW,SAAsB,QAAQ,eACjD,OAAO,QAAQ,sBACe;GAC9B;GACA,YAAY,MAAM;GAClB,QAAQ,MAAM;GACd,QAAQ,MAAM;EAChB,CAAC;EACD,MAAM,MAAM,cAAc,KAAK,UAAU,WAAW,IAAI,KAAA;EACxD,MAAM,OAAO,MAAM,QAAQ,aAAa,OAAO,QAAQ;EACvD,MAAM,MAAM,OAAO,oBAAC,MAAD,CAAiB,GAAN,GAAM,IAAI,oBAAC,QAAD,CAAS,CAAA;EAEjD,IAAI,MAAM,iBACR,MAAM,gBAAgB,OAAO,uBAAuB;EAGtD,IAAI,MAAM,eACR,MAAM,gBAAgB,OAAO,mBAAmB;EAGlD,IAAI,MAAM,WAAW,WACnB,MAAM,gBAAgB,OAAO,aAAa;EAG5C,IAAI,MAAM,WAAW,YAAY;GAC/B,IAAI,CAAC,WAAW,MAAM,KAAK,GAAG;IAC5B,IAAA,QAAA,IAAA,aAA6B,cAC3B,MAAM,IAAI,MAAM,6CAA6C;IAG/D,UAAU;GACZ;GACA,OAAO,oBAAoB,QAAQ,OAAO,MAAM,KAAK;EACvD;EAEA,IAAI,MAAM,WAAW,cAAc;GACjC,IAAI,CAAC,WAAW,MAAM,KAAK,GAAG;IAC5B,IAAA,QAAA,IAAA,aAA6B,cAC3B,MAAM,IAAI,MAAM,6CAA6C;IAG/D,UAAU;GACZ;GACA,MAAM,gBAAgB,OAAO,aAAa;EAC5C;EAEA,IAAI,MAAM,WAAW,SAKnB,OACE,qBAJC,MAAM,QAAQ,kBACb,OAAO,QAAQ,0BACjB,gBAEA;GACE,OAAO,MAAM;GACb,OAAO,KAAA;GACP,MAAM,EACJ,gBAAgB,GAClB;EACD,CAAA;EAIL,OAAO;CACT;CAEA,MAAM,aAAa,OAAO,OAAO,YAAY,IAAI,OAAO;CACxD,IAAI,CAAC,YAAY;EACf,IAAA,QAAA,IAAA,aAA6B,cAC3B,MAAM,IAAI,MACR,uDAAuD,QAAQ,yBACjE;EAGF,UAAU;CACZ;CAEA,MAAM,QAAQ,SAAS,aAAa,UAAU,KAAK;CACnD,MAAM,UAAU,MAAM;CACtB,MAAM,QAAQ,OAAO,WAAW;CAEhC,MAAM,MAAM,QAAM,cAAc;EAI9B,MAAM,eAFH,OAAO,WAAW,SAAsB,QAAQ,eACjD,OAAO,QAAQ,sBACe;GAC9B;GACA,YAAY,MAAM;GAClB,QAAQ,MAAM;GACd,QAAQ,MAAM;EAChB,CAAC;EACD,OAAO,cAAc,KAAK,UAAU,WAAW,IAAI,KAAA;CACrD,GAAG;EACD;EACA,MAAM;EACN,MAAM;EACN,MAAM;EACN,OAAO,QAAQ;EACf,OAAO;CACT,CAAC;CAGD,MAAM,MAAM,QAAM,cAAc;EAC9B,MAAM,OAAO,MAAM,QAAQ,aAAa,OAAO,QAAQ;EACvD,IAAI,MACF,OAAO,oBAAC,MAAD,CAAiB,GAAN,GAAM;EAE1B,OAAO,oBAAC,QAAD,CAAS,CAAA;CAClB,GAAG;EAAC;EAAK,MAAM,QAAQ;EAAW,OAAO,QAAQ;CAAgB,CAAC;CAElE,IAAI,MAAM,iBACR,MAAM,gBAAgB,OAAO,uBAAuB;CAGtD,IAAI,MAAM,eACR,MAAM,gBAAgB,OAAO,mBAAmB;CAIlD,IAAI,MAAM,WAAW,WAAW;EAE9B,MAAM,eACJ,MAAM,QAAQ,gBAAgB,OAAO,QAAQ;EAC/C,IAAI,cAAc;GAChB,MAAM,cAAc,OAAO,SAAS,MAAM,EAAE;GAC5C,IAAI,eAAe,CAAC,YAAY,aAAa;QAEvC,EAAE,YAAY,OAAO,WAAW;KAClC,MAAM,oBAAoB,wBAA8B;KAExD,YAAY,aAAa,oBAAoB;KAE7C,iBAAiB;MACf,kBAAkB,QAAQ;MAE1B,YAAY,aAAa,oBAAoB,KAAA;KAC/C,GAAG,YAAY;IACjB;;EAEJ;EACA,MAAM,gBAAgB,OAAO,aAAa;CAC5C;CAEA,IAAI,MAAM,WAAW,YAAY;EAC/B,IAAI,CAAC,WAAW,MAAM,KAAK,GAAG;GAC5B,IAAA,QAAA,IAAA,aAA6B,cAC3B,MAAM,IAAI,MAAM,6CAA6C;GAG/D,UAAU;EACZ;EACA,OAAO,oBAAoB,QAAQ,OAAO,MAAM,KAAK;CACvD;CAEA,IAAI,MAAM,WAAW,cAAc;EAKjC,IAAI,CAAC,WAAW,MAAM,KAAK,GAAG;GAC5B,IAAA,QAAA,IAAA,aAA6B,cAC3B,MAAM,IAAI,MAAM,6CAA6C;GAG/D,UAAU;EACZ;EAEA,MAAM,gBAAgB,OAAO,aAAa;CAC5C;CAEA,IAAI,MAAM,WAAW,SAAS;EAM5B,IAAI,YAAY,OAAO,UAKrB,OACE,qBAJC,MAAM,QAAQ,kBACb,OAAO,QAAQ,0BACjB,gBAEA;GACE,OAAO,MAAM;GACb,OAAO,KAAA;GACP,MAAM,EACJ,gBAAgB,GAClB;EACD,CAAA;EAIL,MAAM,MAAM;CACd;CAEA,OAAO;AACT,CAAC;;;;;;;AAQD,IAAa,SAAS,QAAM,KAAK,SAAS,aAAa;CACrD,MAAM,SAAS,UAAU;CACzB,MAAM,UAAU,QAAM,WAAW,YAAY;CAE7C,IAAI;CACJ,IAAI,uBAAuB;CAC3B,IAAI;CAEJ,IAAI,YAAY,OAAO,UAAU;EAC/B,MAAM,UAAU,OAAO,OAAO,QAAQ,IAAI;EAC1C,MAAM,cAAc,UAChB,QAAQ,WAAW,UAAU,MAAM,OAAO,OAAO,IACjD;EACJ,MAAM,cAAc,eAAe,IAAI,QAAQ,eAAe,KAAA;EAC9D,UAAU,aAAa;EACvB,uBAAuB,aAAa,kBAAkB;EACtD,eACE,eAAe,IAAK,QAAQ,cAAc,IAAI,KAAgB,KAAA;CAClE,OAAO;EAGL,MAAM,mBAAmB,UACrB,OAAO,OAAO,YAAY,IAAI,OAAO,IACrC,KAAA;EAGH,CAAC,SAAS,wBAAwB,SACjC,mBACC,UAAgC,CAC/B,OAAO,SACP,OAAO,kBAAkB,KAC3B,GACA,yBACF;EAGA,eAAe,SAAS,OAAO,OAAO,YAAY,QAAQ;GAExD,OAAO,IADO,IAAI,WAAW,OAAO,OAAO,OAChC,IAAQ;EACrB,CAAC;CACH;CAEA,MAAM,QAAQ,UAAU,OAAO,WAAW,WAAW,KAAA;CAErD,MAAM,iBAAiB,OAAO,QAAQ,0BACpC,oBAAC,OAAO,QAAQ,yBAAhB,CAAyC,CAAA,IACvC;CAEJ,IAAI,sBAAsB;EACxB,IAAI,CAAC,OAAO;GACV,IAAA,QAAA,IAAA,aAA6B,cAC3B,MAAM,IAAI,MACR,6DACF;GAGF,UAAU;EACZ;EACA,OAAO,oBAAoB,QAAQ,OAAO,KAAA,CAAS;CACrD;CAEA,IAAI,CAAC,cACH,OAAO;CAGT,MAAM,YAAY,oBAAC,OAAD,EAAO,SAAS,aAAe,CAAA;CAEjD,IAAI,YAAY,aACd,OACE,oBAAC,QAAM,UAAP;EAAgB,UAAU;YAAiB;CAA0B,CAAA;CAIzE,OAAO;AACT,CAAC"} | ||
| {"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 { isNotFound, rootRouteId } 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 type {\n AnyRoute,\n AnyRouteMatch,\n RootRouteOptions,\n} from '@tanstack/router-core'\n\nexport function renderPending(\n router: ReturnType<typeof useRouter>,\n route?: AnyRoute,\n) {\n const PendingComponent =\n route?.options.pendingComponent ?? router.options.defaultPendingComponent\n return PendingComponent ? <PendingComponent /> : null\n}\n\ntype OutletMatchSelection = [\n parentGlobalNotFound: boolean,\n parentNotFoundError: unknown,\n]\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 routeId,\n}: {\n routeId: string\n}) {\n const router = useRouter()\n\n if (isServer ?? router.isServer) {\n const match = router.stores.byRoute.get(routeId)!.get()!\n return <MatchView router={router} match={match} />\n }\n\n const matchStore = router.stores.getMatchStore(routeId)\n // eslint-disable-next-line react-hooks/rules-of-hooks\n const match = useStore(matchStore, (value) => value)\n return <MatchView router={router} match={match!} />\n})\n\nfunction MatchView({\n router,\n match,\n}: {\n router: ReturnType<typeof useRouter>\n match: AnyRouteMatch\n}) {\n const route: AnyRoute = router.routesById[match.routeId]\n\n const pendingElement = renderPending(router, route)\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 _notFound 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 = match.ssr === false || match.ssr === 'data-only'\n const ResolvedSuspenseBoundary =\n (route.options.wrapInSuspense ??\n pendingElement ??\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={match.routeId}>\n <ResolvedSuspenseBoundary fallback={pendingElement}>\n <ResolvedCatchBoundary\n getResetKey={() => match}\n errorComponent={routeErrorComponent as any}\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 ??= match.routeId\n throw error\n }\n if (process.env.NODE_ENV !== 'production') {\n console.warn(`Warning: Error in route match: ${match.id}`)\n }\n routeOnCatch?.(error, errorInfo)\n }}\n >\n <ResolvedNotFoundBoundary\n fallback={(error) => {\n error.routeId ??= match.routeId\n\n if (error.routeId !== match.routeId) {\n throw error\n }\n\n return React.createElement(\n routeNotFoundComponent!,\n error as any,\n )\n }}\n >\n {resolvedNoSsr ? (\n <ClientOnly fallback={pendingElement}>\n <MatchInner match={match} />\n </ClientOnly>\n ) : (\n <MatchInner match={match} />\n )}\n </ResolvedNotFoundBoundary>\n </ResolvedCatchBoundary>\n </ResolvedSuspenseBoundary>\n </matchContext.Provider>\n {(isServer ?? router.isServer) &&\n route.parentRoute?.id === rootRouteId &&\n router.options.scrollRestoration ? (\n <ScrollRestoration />\n ) : null}\n </ShellComponent>\n )\n}\n\nexport const MatchInner = React.memo(function MatchInnerImpl({\n match,\n}: {\n match: AnyRouteMatch\n}): any {\n const router = useRouter()\n const routeId = match.routeId\n const route = router.routesById[routeId] as AnyRoute\n const key = React.useMemo(() => {\n const remountFn =\n route.options.remountDeps ?? 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 route.options.remountDeps,\n router.options.defaultRemountDeps,\n ])\n const out = React.useMemo(() => {\n const Comp = route.options.component ?? router.options.defaultComponent\n return Comp ? <Comp key={key} /> : <Outlet />\n }, [key, route.options.component, router.options.defaultComponent])\n\n if (match.status === 'pending') {\n if (router._tx) {\n throw router._tx[5]\n }\n return renderPending(router, route)\n }\n\n if (match.status === 'notFound') {\n return renderRouteNotFound(router, route, match.error)\n }\n\n if (match.status === 'error') {\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 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 routeId = React.useContext(matchContext)!\n\n let parentGlobalNotFound: boolean\n let parentNotFoundError: unknown\n let childRouteId: string | undefined\n\n if (isServer ?? router.isServer) {\n const matches = router.stores.matches.get()\n const parentIndex = matches.findIndex((match) => match.routeId === routeId)\n const parentMatch = matches[parentIndex]!\n parentGlobalNotFound = !!parentMatch._notFound\n parentNotFoundError = parentMatch.error\n childRouteId = matches[parentIndex + 1]?.routeId\n } else {\n const parentMatchStore = router.stores.getMatchStore(routeId)\n\n // eslint-disable-next-line react-hooks/rules-of-hooks\n ;[parentGlobalNotFound, parentNotFoundError] = useStore(\n parentMatchStore,\n (match): OutletMatchSelection => [!!match!._notFound, match!.error],\n outletMatchSelectionEqual,\n )\n\n // eslint-disable-next-line react-hooks/rules-of-hooks\n childRouteId = useStore(router.stores.ids, (ids) => {\n return ids[ids.indexOf(routeId) + 1]\n })\n }\n\n if (parentGlobalNotFound) {\n return renderRouteNotFound(\n router,\n router.routesById[routeId],\n parentNotFoundError,\n )\n }\n\n if (!childRouteId) {\n return null\n }\n\n const nextMatch = <Match routeId={childRouteId} />\n\n if (routeId === rootRouteId) {\n return (\n <React.Suspense fallback={renderPending(router)}>\n {nextMatch}\n </React.Suspense>\n )\n }\n\n return nextMatch\n})\n"],"mappings":"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"} |
@@ -49,21 +49,10 @@ import { StructuralSharingOption, ValidateSelected } from './structuralSharing.js'; | ||
| /** | ||
| * Read the full array of active route matches or select a derived subset. | ||
| * | ||
| * Useful for debugging, breadcrumbs, or aggregating metadata across matches. | ||
| * | ||
| * @returns The array of matches (or the selected value). | ||
| * @link https://tanstack.com/router/latest/docs/framework/react/api/router/useMatchesHook | ||
| * Read the presented route matches above the current match, or select a | ||
| * derived value from them. | ||
| */ | ||
| /** | ||
| * Read the full array of active route matches or select a derived subset. | ||
| * | ||
| * Useful for debugging, breadcrumbs, or aggregating metadata across matches. | ||
| * | ||
| * @link https://tanstack.com/router/latest/docs/framework/react/api/router/useMatchesHook | ||
| */ | ||
| export declare function useParentMatches<TRouter extends AnyRouter = RegisteredRouter, TSelected = unknown, TStructuralSharing extends boolean = boolean>(opts?: UseMatchesBaseOptions<TRouter, TSelected, TStructuralSharing> & StructuralSharingOption<TRouter, TSelected, TStructuralSharing>): UseMatchesResult<TRouter, TSelected>; | ||
| /** | ||
| * Read the array of active route matches that are children of the current | ||
| * match (or selected parent) in the match tree. | ||
| * Read the presented route matches below the current match, or select a | ||
| * derived value from them. | ||
| */ | ||
| export declare function useChildMatches<TRouter extends AnyRouter = RegisteredRouter, TSelected = unknown, TStructuralSharing extends boolean = boolean>(opts?: UseMatchesBaseOptions<TRouter, TSelected, TStructuralSharing> & StructuralSharingOption<TRouter, TSelected, TStructuralSharing>): UseMatchesResult<TRouter, TSelected>; |
+33
-36
| "use client"; | ||
| import { CatchBoundary, ErrorComponent } from "./CatchBoundary.js"; | ||
| import { useLayoutEffect } from "./utils.js"; | ||
| import { CatchBoundary } from "./CatchBoundary.js"; | ||
| import { matchContext } from "./matchContext.js"; | ||
@@ -8,8 +9,8 @@ import { useRouter } from "./useRouter.js"; | ||
| import { SafeFragment } from "./SafeFragment.js"; | ||
| import { Match } from "./Match.js"; | ||
| import { Match, renderPending } from "./Match.js"; | ||
| import { rootRouteId } from "@tanstack/router-core"; | ||
| import * as React$1 from "react"; | ||
| import { jsx, jsxs } from "react/jsx-runtime"; | ||
| import { isServer } from "@tanstack/router-core/isServer"; | ||
| import { Fragment, jsx, jsxs } from "react/jsx-runtime"; | ||
| import { useStore } from "@tanstack/react-store"; | ||
| import { isServer } from "@tanstack/router-core/isServer"; | ||
| //#region src/Matches.tsx | ||
@@ -22,8 +23,9 @@ /** | ||
| const router = useRouter(); | ||
| const PendingComponent = router.routesById[rootRouteId].options.pendingComponent ?? router.options.defaultPendingComponent; | ||
| const pendingElement = PendingComponent ? /* @__PURE__ */ jsx(PendingComponent, {}) : null; | ||
| const inner = /* @__PURE__ */ jsxs((isServer ?? router.isServer) || typeof document !== "undefined" && router.ssr ? SafeFragment : React$1.Suspense, { | ||
| const rootRoute = router.routesById[rootRouteId]; | ||
| const pendingElement = renderPending(router, rootRoute); | ||
| const ResolvedSuspense = (isServer ?? router.isServer) || router.ssr ? SafeFragment : React$1.Suspense; | ||
| const inner = /* @__PURE__ */ jsxs(Fragment, { children: [!(isServer ?? router.isServer) && /* @__PURE__ */ jsx(Transitioner, {}), /* @__PURE__ */ jsx(ResolvedSuspense, { | ||
| fallback: pendingElement, | ||
| children: [!(isServer ?? router.isServer) && /* @__PURE__ */ jsx(Transitioner, {}), /* @__PURE__ */ jsx(MatchesInner, {})] | ||
| }); | ||
| children: /* @__PURE__ */ jsx(MatchesInner, {}) | ||
| })] }); | ||
| return router.options.InnerWrap ? /* @__PURE__ */ jsx(router.options.InnerWrap, { children: inner }) : inner; | ||
@@ -33,11 +35,13 @@ } | ||
| const router = useRouter(); | ||
| const _isServer = isServer ?? router.isServer; | ||
| const matchId = _isServer ? router.stores.firstId.get() : useStore(router.stores.firstId, (id) => id); | ||
| const resetKey = _isServer ? router.stores.loadedAt.get() : useStore(router.stores.loadedAt, (loadedAt) => loadedAt); | ||
| const matchComponent = matchId ? /* @__PURE__ */ jsx(Match, { matchId }) : null; | ||
| const matches = isServer ?? router.isServer ? router.stores.matches.get() : useStore(router.stores.matches, (value) => value); | ||
| const match = matches[0]; | ||
| const routeId = match?.routeId; | ||
| useLayoutEffect(() => { | ||
| router._rendered(matches); | ||
| }, [matches, router]); | ||
| const matchComponent = routeId ? /* @__PURE__ */ jsx(Match, { routeId }) : null; | ||
| return /* @__PURE__ */ jsx(matchContext.Provider, { | ||
| value: matchId, | ||
| value: routeId, | ||
| children: router.options.disableGlobalCatchBoundary ? matchComponent : /* @__PURE__ */ jsx(CatchBoundary, { | ||
| getResetKey: () => resetKey, | ||
| errorComponent: ErrorComponent, | ||
| getResetKey: () => match, | ||
| onCatch: process.env.NODE_ENV !== "production" ? (error) => { | ||
@@ -65,3 +69,7 @@ console.warn(`Warning: The following error wasn't caught by any route! At the very least, consider setting an 'errorComponent' in your RootRoute!`); | ||
| const router = useRouter(); | ||
| if (!(isServer ?? router.isServer)) useStore(router.stores.matchRouteDeps, (d) => d); | ||
| if (!(isServer ?? router.isServer)) { | ||
| useStore(router.stores.location, (location) => location.href); | ||
| useStore(router.stores.resolvedLocation, (location) => location?.href); | ||
| useStore(router.stores.status, (status) => status); | ||
| } | ||
| return React$1.useCallback((opts) => { | ||
@@ -98,21 +106,10 @@ const { pending, caseSensitive, fuzzy, includeSearch, ...rest } = opts; | ||
| /** | ||
| * Read the full array of active route matches or select a derived subset. | ||
| * | ||
| * Useful for debugging, breadcrumbs, or aggregating metadata across matches. | ||
| * | ||
| * @returns The array of matches (or the selected value). | ||
| * @link https://tanstack.com/router/latest/docs/framework/react/api/router/useMatchesHook | ||
| * Read the presented route matches above the current match, or select a | ||
| * derived value from them. | ||
| */ | ||
| /** | ||
| * Read the full array of active route matches or select a derived subset. | ||
| * | ||
| * Useful for debugging, breadcrumbs, or aggregating metadata across matches. | ||
| * | ||
| * @link https://tanstack.com/router/latest/docs/framework/react/api/router/useMatchesHook | ||
| */ | ||
| function useParentMatches(opts) { | ||
| const contextMatchId = React$1.useContext(matchContext); | ||
| const contextRouteId = React$1.useContext(matchContext); | ||
| return useMatches({ | ||
| select: (matches) => { | ||
| matches = matches.slice(0, matches.findIndex((d) => d.id === contextMatchId)); | ||
| matches = matches.slice(0, matches.findIndex((d) => d.routeId === contextRouteId)); | ||
| return opts?.select ? opts.select(matches) : matches; | ||
@@ -124,10 +121,10 @@ }, | ||
| /** | ||
| * Read the array of active route matches that are children of the current | ||
| * match (or selected parent) in the match tree. | ||
| * Read the presented route matches below the current match, or select a | ||
| * derived value from them. | ||
| */ | ||
| function useChildMatches(opts) { | ||
| const contextMatchId = React$1.useContext(matchContext); | ||
| const contextRouteId = React$1.useContext(matchContext); | ||
| return useMatches({ | ||
| select: (matches) => { | ||
| matches = matches.slice(matches.findIndex((d) => d.id === contextMatchId) + 1); | ||
| matches = matches.slice(matches.findIndex((d) => d.routeId === contextRouteId) + 1); | ||
| return opts?.select ? opts.select(matches) : matches; | ||
@@ -134,0 +131,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 { 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":";;;;;;;;;;;;;;;;;;AA8CA,SAAgB,UAAU;CACxB,MAAM,SAAS,UAAU;CAGzB,MAAM,mBAFsB,OAAO,WAAW,aAGlC,QAAQ,oBAAoB,OAAO,QAAQ;CAEvD,MAAM,iBAAiB,mBAAmB,oBAAC,kBAAD,CAAmB,CAAA,IAAI;CASjE,MAAM,QACJ,sBANC,YAAY,OAAO,aACnB,OAAO,aAAa,eAAe,OAAO,MACvC,eACA,QAAM,UAGV;EAAkB,UAAU;YAA5B,CACG,EAAE,YAAY,OAAO,aAAa,oBAAC,cAAD,CAAe,CAAA,GAClD,oBAAC,cAAD,CAAe,CAAA,CACC;;CAGpB,OAAO,OAAO,QAAQ,YACpB,oBAAC,OAAO,QAAQ,WAAhB,EAAA,UAA2B,MAAgC,CAAA,IAE3D;AAEJ;AAEA,SAAS,eAAe;CACtB,MAAM,SAAS,UAAU;CACzB,MAAM,YAAY,YAAY,OAAO;CACrC,MAAM,UAAU,YACZ,OAAO,OAAO,QAAQ,IAAI,IAE1B,SAAS,OAAO,OAAO,UAAU,OAAO,EAAE;CAC9C,MAAM,WAAW,YACb,OAAO,OAAO,SAAS,IAAI,IAE3B,SAAS,OAAO,OAAO,WAAW,aAAa,QAAQ;CAE3D,MAAM,iBAAiB,UAAU,oBAAC,OAAD,EAAgB,QAAU,CAAA,IAAI;CAE/D,OACE,oBAAC,aAAa,UAAd;EAAuB,OAAO;YAC3B,OAAO,QAAQ,6BACd,iBAEA,oBAAC,eAAD;GACE,mBAAmB;GACnB,gBAAgB;GAChB,SAAA,QAAA,IAAA,aAC2B,gBACpB,UAAU;IACT,QAAQ,KACN,qIACF;IACA,QAAQ,KAAK,YAAY,MAAM,WAAW,MAAM,SAAS,GAAG;GAC9D,IACA,KAAA;aAGL;EACY,CAAA;CAEI,CAAA;AAE3B;;;;;;;;;;;;;AA0BA,SAAgB,gBAA8D;CAC5E,MAAM,SAAS,UAAU;CAEzB,IAAI,EAAE,YAAY,OAAO,WAEvB,SAAS,OAAO,OAAO,iBAAiB,MAAM,CAAC;CAGjD,OAAO,QAAM,aAOT,SAGqE;EACrE,MAAM,EAAE,SAAS,eAAe,OAAO,eAAe,GAAG,SAAS;EAElE,OAAO,OAAO,WAAW,MAAa;GACpC;GACA;GACA;GACA;EACF,CAAC;CACH,GACA,CAAC,MAAM,CACT;AACF;;;;;;;;AA0BA,SAAgB,WAMd,OAA4E;CAE5E,MAAM,SADa,cACJ,EAAW,KAAY;CAEtC,IAAI,OAAO,MAAM,aAAa,YAC5B,OAAQ,MAAM,SAAiB,MAAM;CAGvC,OAAO,SAAS,MAAM,WAAW;AACnC;AAiBA,SAAgB,WAKd,MAEsC;CACtC,MAAM,SAAS,UAAmB;CAElC,IAAI,YAAY,OAAO,UAAU;EAC/B,MAAM,UAAU,OAAO,OAAO,QAAQ,IAAI;EAG1C,OAAQ,MAAM,SAAS,KAAK,OAAO,OAAO,IAAI;CAIhD;CAGA,OAAO,SACL,OAAO,OAAO,SAEd,qBAAqB,MAAM,MAAM,CACnC;AACF;;;;;;;;;;;;;;;;AAkBA,SAAgB,iBAKd,MAEsC;CACtC,MAAM,iBAAiB,QAAM,WAAW,YAAY;CAEpD,OAAO,WAAW;EAChB,SAAS,YAAiD;GACxD,UAAU,QAAQ,MAChB,GACA,QAAQ,WAAW,MAAM,EAAE,OAAO,cAAc,CAClD;GACA,OAAO,MAAM,SAAS,KAAK,OAAO,OAAO,IAAI;EAC/C;EACA,mBAAmB,MAAM;CAC3B,CAAQ;AACV;;;;;AAMA,SAAgB,gBAKd,MAEsC;CACtC,MAAM,iBAAiB,QAAM,WAAW,YAAY;CAEpD,OAAO,WAAW;EAChB,SAAS,YAAiD;GACxD,UAAU,QAAQ,MAChB,QAAQ,WAAW,MAAM,EAAE,OAAO,cAAc,IAAI,CACtD;GACA,OAAO,MAAM,SAAS,KAAK,OAAO,OAAO,IAAI;EAC/C;EACA,mBAAmB,MAAM;CAC3B,CAAQ;AACV"} | ||
| {"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 } from './CatchBoundary'\nimport { useRouter } from './useRouter'\nimport { useStructuralSharing } from './useMatch'\nimport { useLayoutEffect } from './utils'\nimport { Transitioner } from './Transitioner'\nimport { matchContext } from './matchContext'\nimport { Match, renderPending } 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 pendingElement = renderPending(router, rootRoute)\n\n // Do not render a root Suspense during SSR or hydrating from SSR\n const ResolvedSuspense =\n (isServer ?? router.isServer) || router.ssr ? SafeFragment : React.Suspense\n\n const inner = (\n <>\n {!(isServer ?? router.isServer) && <Transitioner />}\n <ResolvedSuspense fallback={pendingElement}>\n <MatchesInner />\n </ResolvedSuspense>\n </>\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 matches =\n (isServer ?? router.isServer)\n ? router.stores.matches.get()\n : // eslint-disable-next-line react-hooks/rules-of-hooks\n useStore(router.stores.matches, (value) => value)\n const match = matches[0]\n const routeId = match?.routeId\n\n useLayoutEffect(() => {\n router._rendered!(matches)\n }, [matches, router])\n\n const matchComponent = routeId ? <Match routeId={routeId} /> : null\n\n return (\n <matchContext.Provider value={routeId}>\n {router.options.disableGlobalCatchBoundary ? (\n matchComponent\n ) : (\n <CatchBoundary\n getResetKey={() => match}\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.location, (location) => location.href)\n // eslint-disable-next-line react-hooks/rules-of-hooks\n useStore(router.stores.resolvedLocation, (location) => location?.href)\n // eslint-disable-next-line react-hooks/rules-of-hooks\n useStore(router.stores.status, (status) => status)\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 presented route matches above the current match, or select a\n * derived value from them.\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 contextRouteId = React.useContext(matchContext)\n\n return useMatches({\n select: (matches: Array<MakeRouteMatchUnion<TRouter>>) => {\n matches = matches.slice(\n 0,\n matches.findIndex((d) => d.routeId === contextRouteId),\n )\n return opts?.select ? opts.select(matches) : matches\n },\n structuralSharing: opts?.structuralSharing,\n } as any)\n}\n\n/**\n * Read the presented route matches below the current match, or select a\n * derived value from them.\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 contextRouteId = React.useContext(matchContext)\n\n return useMatches({\n select: (matches: Array<MakeRouteMatchUnion<TRouter>>) => {\n matches = matches.slice(\n matches.findIndex((d) => d.routeId === contextRouteId) + 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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"} |
@@ -5,5 +5,5 @@ import { CatchBoundary } from "./CatchBoundary.js"; | ||
| import "react"; | ||
| import { isServer } from "@tanstack/router-core/isServer"; | ||
| import { jsx } from "react/jsx-runtime"; | ||
| import { useStore } from "@tanstack/react-store"; | ||
| import { isServer } from "@tanstack/router-core/isServer"; | ||
| //#region src/not-found.tsx | ||
@@ -10,0 +10,0 @@ function CatchNotFound(props) { |
@@ -11,4 +11,4 @@ import { AnyRouter, RegisteredRouter, RouterOptions } from '@tanstack/router-core'; | ||
| /** | ||
| * Top-level component that renders the active route matches and provides the | ||
| * router to the React tree via context. | ||
| * Renders the current match presentation and provides the router to the React | ||
| * tree via context. | ||
| * | ||
@@ -15,0 +15,0 @@ * Accepts the same options as `createRouter` via props to update the router |
@@ -29,4 +29,4 @@ "use client"; | ||
| /** | ||
| * Top-level component that renders the active route matches and provides the | ||
| * router to the React tree via context. | ||
| * Renders the current match presentation and provides the router to the React | ||
| * tree via context. | ||
| * | ||
@@ -33,0 +33,0 @@ * Accepts the same options as `createRouter` via props to update the router |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"RouterProvider.js","names":[],"sources":["../../src/RouterProvider.tsx"],"sourcesContent":["'use client'\n\nimport * as React from 'react'\nimport { hasKeys } from '@tanstack/router-core'\nimport { Matches } from './Matches'\nimport { routerContext } from './routerContext'\nimport type {\n AnyRouter,\n RegisteredRouter,\n RouterOptions,\n} from '@tanstack/router-core'\n\n/**\n * Low-level provider that places the router into React context and optionally\n * updates router options from props. Most apps should use `RouterProvider`.\n */\nexport function RouterContextProvider<\n TRouter extends AnyRouter = RegisteredRouter,\n TDehydrated extends Record<string, any> = Record<string, any>,\n>({\n router,\n children,\n ...rest\n}: RouterProps<TRouter, TDehydrated> & {\n children: React.ReactNode\n}) {\n if (hasKeys(rest)) {\n // Allow the router to update options on the router instance\n router.update({\n ...router.options,\n ...rest,\n context: {\n ...router.options.context,\n ...rest.context,\n },\n })\n }\n\n const provider = (\n <routerContext.Provider value={router as AnyRouter}>\n {children}\n </routerContext.Provider>\n )\n\n if (router.options.Wrap) {\n return <router.options.Wrap>{provider}</router.options.Wrap>\n }\n\n return provider\n}\n\n/**\n * Top-level component that renders the active route matches and provides the\n * router to the React tree via context.\n *\n * Accepts the same options as `createRouter` via props to update the router\n * instance after creation.\n *\n * @link https://tanstack.com/router/latest/docs/framework/react/api/router/createRouterFunction\n */\nexport function RouterProvider<\n TRouter extends AnyRouter = RegisteredRouter,\n TDehydrated extends Record<string, any> = Record<string, any>,\n>({ router, ...rest }: RouterProps<TRouter, TDehydrated>) {\n return (\n <RouterContextProvider router={router} {...rest}>\n <Matches />\n </RouterContextProvider>\n )\n}\n\nexport type RouterProps<\n TRouter extends AnyRouter = RegisteredRouter,\n TDehydrated extends Record<string, any> = Record<string, any>,\n> = Omit<\n RouterOptions<\n TRouter['routeTree'],\n NonNullable<TRouter['options']['trailingSlash']>,\n NonNullable<TRouter['options']['defaultStructuralSharing']>,\n TRouter['history'],\n TDehydrated\n >,\n 'context'\n> & {\n router: TRouter\n context?: Partial<\n RouterOptions<\n TRouter['routeTree'],\n NonNullable<TRouter['options']['trailingSlash']>,\n NonNullable<TRouter['options']['defaultStructuralSharing']>,\n TRouter['history'],\n TDehydrated\n >['context']\n >\n}\n"],"mappings":";;;;;;;;;;;AAgBA,SAAgB,sBAGd,EACA,QACA,UACA,GAAG,QAGF;CACD,IAAI,QAAQ,IAAI,GAEd,OAAO,OAAO;EACZ,GAAG,OAAO;EACV,GAAG;EACH,SAAS;GACP,GAAG,OAAO,QAAQ;GAClB,GAAG,KAAK;EACV;CACF,CAAC;CAGH,MAAM,WACJ,oBAAC,cAAc,UAAf;EAAwB,OAAO;EAC5B;CACqB,CAAA;CAG1B,IAAI,OAAO,QAAQ,MACjB,OAAO,oBAAC,OAAO,QAAQ,MAAhB,EAAA,UAAsB,SAA8B,CAAA;CAG7D,OAAO;AACT;;;;;;;;;;AAWA,SAAgB,eAGd,EAAE,QAAQ,GAAG,QAA2C;CACxD,OACE,oBAAC,uBAAD;EAA+B;EAAQ,GAAI;YACzC,oBAAC,SAAD,CAAU,CAAA;CACW,CAAA;AAE3B"} | ||
| {"version":3,"file":"RouterProvider.js","names":[],"sources":["../../src/RouterProvider.tsx"],"sourcesContent":["'use client'\n\nimport * as React from 'react'\nimport { hasKeys } from '@tanstack/router-core'\nimport { Matches } from './Matches'\nimport { routerContext } from './routerContext'\nimport type {\n AnyRouter,\n RegisteredRouter,\n RouterOptions,\n} from '@tanstack/router-core'\n\n/**\n * Low-level provider that places the router into React context and optionally\n * updates router options from props. Most apps should use `RouterProvider`.\n */\nexport function RouterContextProvider<\n TRouter extends AnyRouter = RegisteredRouter,\n TDehydrated extends Record<string, any> = Record<string, any>,\n>({\n router,\n children,\n ...rest\n}: RouterProps<TRouter, TDehydrated> & {\n children: React.ReactNode\n}) {\n if (hasKeys(rest)) {\n // Allow the router to update options on the router instance\n router.update({\n ...router.options,\n ...rest,\n context: {\n ...router.options.context,\n ...rest.context,\n },\n })\n }\n\n const provider = (\n <routerContext.Provider value={router as AnyRouter}>\n {children}\n </routerContext.Provider>\n )\n\n if (router.options.Wrap) {\n return <router.options.Wrap>{provider}</router.options.Wrap>\n }\n\n return provider\n}\n\n/**\n * Renders the current match presentation and provides the router to the React\n * tree via context.\n *\n * Accepts the same options as `createRouter` via props to update the router\n * instance after creation.\n *\n * @link https://tanstack.com/router/latest/docs/framework/react/api/router/createRouterFunction\n */\nexport function RouterProvider<\n TRouter extends AnyRouter = RegisteredRouter,\n TDehydrated extends Record<string, any> = Record<string, any>,\n>({ router, ...rest }: RouterProps<TRouter, TDehydrated>) {\n return (\n <RouterContextProvider router={router} {...rest}>\n <Matches />\n </RouterContextProvider>\n )\n}\n\nexport type RouterProps<\n TRouter extends AnyRouter = RegisteredRouter,\n TDehydrated extends Record<string, any> = Record<string, any>,\n> = Omit<\n RouterOptions<\n TRouter['routeTree'],\n NonNullable<TRouter['options']['trailingSlash']>,\n NonNullable<TRouter['options']['defaultStructuralSharing']>,\n TRouter['history'],\n TDehydrated\n >,\n 'context'\n> & {\n router: TRouter\n context?: Partial<\n RouterOptions<\n TRouter['routeTree'],\n NonNullable<TRouter['options']['trailingSlash']>,\n NonNullable<TRouter['options']['defaultStructuralSharing']>,\n TRouter['history'],\n TDehydrated\n >['context']\n >\n}\n"],"mappings":";;;;;;;;;;;AAgBA,SAAgB,sBAGd,EACA,QACA,UACA,GAAG,QAGF;CACD,IAAI,QAAQ,IAAI,GAEd,OAAO,OAAO;EACZ,GAAG,OAAO;EACV,GAAG;EACH,SAAS;GACP,GAAG,OAAO,QAAQ;GAClB,GAAG,KAAK;EACV;CACF,CAAC;CAGH,MAAM,WACJ,oBAAC,cAAc,UAAf;EAAwB,OAAO;EAC5B;CACqB,CAAA;CAG1B,IAAI,OAAO,QAAQ,MACjB,OAAO,oBAAC,OAAO,QAAQ,MAAhB,EAAA,UAAsB,SAA8B,CAAA;CAG7D,OAAO;AACT;;;;;;;;;;AAWA,SAAgB,eAGd,EAAE,QAAQ,GAAG,QAA2C;CACxD,OACE,oBAAC,uBAAD;EAA+B;EAAQ,GAAI;YACzC,oBAAC,SAAD,CAAU,CAAA;CACW,CAAA;AAE3B"} |
| import { createNonReactiveMutableStore, createNonReactiveReadonlyStore } from "@tanstack/router-core"; | ||
| import { isServer } from "@tanstack/router-core/isServer"; | ||
| import { batch, createAtom } from "@tanstack/react-store"; | ||
| import { isServer } from "@tanstack/router-core/isServer"; | ||
| //#region src/routerStores.ts | ||
@@ -5,0 +5,0 @@ var getStoreFactory = (opts) => { |
| import { useRouter } from "./useRouter.js"; | ||
| import { isServer } from "@tanstack/router-core/isServer"; | ||
| import { jsx } from "react/jsx-runtime"; | ||
| import { isServer } from "@tanstack/router-core/isServer"; | ||
| //#region src/ScriptOnce.tsx | ||
@@ -5,0 +5,0 @@ /** |
+23
-29
| import { useRouter } from "./useRouter.js"; | ||
| import { Asset } from "./Asset.js"; | ||
| import { deepEqual } from "@tanstack/router-core"; | ||
| import { _getAssetMatches, deepEqual } from "@tanstack/router-core"; | ||
| import { createElement } from "react"; | ||
| import { isServer } from "@tanstack/router-core/isServer"; | ||
| import { Fragment, jsx } from "react/jsx-runtime"; | ||
| import { useStore } from "@tanstack/react-store"; | ||
| import { isServer } from "@tanstack/router-core/isServer"; | ||
| //#region src/Scripts.tsx | ||
@@ -16,10 +16,19 @@ /** | ||
| const nonce = router.options.ssr?.nonce; | ||
| const getAssetScripts = (matches) => { | ||
| const assetScripts = []; | ||
| const getScripts = (matches) => { | ||
| matches = _getAssetMatches(matches); | ||
| const scripts = matches.flatMap((match) => match.scripts ?? []).filter(Boolean).map(({ children, ...script }) => ({ | ||
| tag: "script", | ||
| attrs: { | ||
| ...script, | ||
| suppressHydrationWarning: true, | ||
| nonce | ||
| }, | ||
| children | ||
| })); | ||
| const manifest = router.ssr?.manifest; | ||
| if (!manifest) return []; | ||
| if (!manifest) return scripts; | ||
| for (const match of matches) { | ||
| const scripts = manifest.routes[match.routeId]?.scripts; | ||
| if (!scripts) continue; | ||
| for (const asset of scripts) assetScripts.push({ | ||
| const manifestScripts = manifest.routes[match.routeId]?.scripts; | ||
| if (!manifestScripts) continue; | ||
| for (const asset of manifestScripts) scripts.push({ | ||
| tag: "script", | ||
@@ -34,28 +43,13 @@ attrs: { | ||
| } | ||
| return assetScripts; | ||
| return scripts; | ||
| }; | ||
| const getScripts = (matches) => matches.map((match) => match.scripts).flat(1).filter(Boolean).map(({ children, ...script }) => ({ | ||
| tag: "script", | ||
| attrs: { | ||
| ...script, | ||
| suppressHydrationWarning: true, | ||
| nonce | ||
| }, | ||
| children | ||
| })); | ||
| if (isServer ?? router.isServer) { | ||
| const activeMatches = router.stores.matches.get(); | ||
| const assetScripts = getAssetScripts(activeMatches); | ||
| return renderScripts(router, getScripts(activeMatches), assetScripts); | ||
| } | ||
| const assetScripts = useStore(router.stores.matches, getAssetScripts, deepEqual); | ||
| return renderScripts(router, useStore(router.stores.matches, getScripts, deepEqual), assetScripts); | ||
| if (isServer ?? router.isServer) return renderScripts(router, getScripts(router.stores.matches.get())); | ||
| return renderScripts(router, useStore(router.stores.matches, getScripts, deepEqual)); | ||
| }; | ||
| function renderScripts(router, scripts, assetScripts) { | ||
| const allScripts = [...scripts, ...assetScripts]; | ||
| function renderScripts(router, scripts) { | ||
| if ((isServer ?? router.isServer) && router.serverSsr) { | ||
| const serverBufferedScript = router.serverSsr.takeBufferedScripts(); | ||
| if (serverBufferedScript) allScripts.unshift(serverBufferedScript); | ||
| if (serverBufferedScript) scripts.unshift(serverBufferedScript); | ||
| } | ||
| return /* @__PURE__ */ jsx(Fragment, { children: allScripts.map((asset, i) => /* @__PURE__ */ createElement(Asset, { | ||
| return /* @__PURE__ */ jsx(Fragment, { children: scripts.map((asset, i) => /* @__PURE__ */ createElement(Asset, { | ||
| ...asset, | ||
@@ -62,0 +56,0 @@ key: `tsr-scripts-${asset.tag}-${i}` |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"Scripts.js","names":[],"sources":["../../src/Scripts.tsx"],"sourcesContent":["import { useStore } from '@tanstack/react-store'\nimport { deepEqual } from '@tanstack/router-core'\nimport { isServer } from '@tanstack/router-core/isServer'\nimport { Asset } from './Asset'\nimport { useRouter } from './useRouter'\nimport type { RouterManagedTag } from '@tanstack/router-core'\n\ntype ScriptRenderAsset = RouterManagedTag & {\n preventScriptHoist?: boolean\n}\n\n/**\n * Render body script tags collected from route matches and SSR manifests.\n * Should be placed near the end of the document body.\n */\nexport const Scripts = () => {\n const router = useRouter()\n const nonce = router.options.ssr?.nonce\n\n const getAssetScripts = (matches: Array<any>) => {\n const assetScripts: Array<ScriptRenderAsset> = []\n const manifest = router.ssr?.manifest\n\n if (!manifest) {\n return []\n }\n\n for (const match of matches) {\n const scripts = manifest.routes[match.routeId]?.scripts\n\n if (!scripts) {\n continue\n }\n\n for (const asset of scripts) {\n assetScripts.push({\n tag: 'script',\n attrs: { ...asset.attrs, nonce },\n children: asset.children,\n ...(typeof asset.attrs?.src === 'string'\n ? { preventScriptHoist: true }\n : {}),\n })\n }\n }\n\n return assetScripts\n }\n\n const getScripts = (matches: Array<any>): Array<RouterManagedTag> =>\n (\n matches\n .map((match) => match.scripts!)\n .flat(1)\n .filter(Boolean) as Array<RouterManagedTag>\n ).map(\n ({ children, ...script }) =>\n ({\n tag: 'script',\n attrs: {\n ...script,\n suppressHydrationWarning: true,\n nonce,\n },\n children,\n }) satisfies RouterManagedTag,\n )\n\n if (isServer ?? router.isServer) {\n const activeMatches = router.stores.matches.get()\n const assetScripts = getAssetScripts(activeMatches)\n const scripts = getScripts(activeMatches)\n return renderScripts(router, scripts, assetScripts)\n }\n\n // eslint-disable-next-line react-hooks/rules-of-hooks -- condition is static\n const assetScripts = useStore(\n router.stores.matches,\n getAssetScripts,\n deepEqual,\n )\n // eslint-disable-next-line react-hooks/rules-of-hooks -- condition is static\n const scripts = useStore(router.stores.matches, getScripts, deepEqual)\n\n return renderScripts(router, scripts, assetScripts)\n}\n\nfunction renderScripts(\n router: ReturnType<typeof useRouter>,\n scripts: Array<RouterManagedTag>,\n assetScripts: Array<ScriptRenderAsset>,\n) {\n const allScripts = [...scripts, ...assetScripts] as Array<ScriptRenderAsset>\n\n if ((isServer ?? router.isServer) && router.serverSsr) {\n const serverBufferedScript = router.serverSsr.takeBufferedScripts()\n if (serverBufferedScript) {\n allScripts.unshift(serverBufferedScript)\n }\n }\n\n return (\n <>\n {allScripts.map((asset, i) => (\n <Asset {...asset} key={`tsr-scripts-${asset.tag}-${i}`} />\n ))}\n </>\n )\n}\n"],"mappings":";;;;;;;;;;;;AAeA,IAAa,gBAAgB;CAC3B,MAAM,SAAS,UAAU;CACzB,MAAM,QAAQ,OAAO,QAAQ,KAAK;CAElC,MAAM,mBAAmB,YAAwB;EAC/C,MAAM,eAAyC,CAAC;EAChD,MAAM,WAAW,OAAO,KAAK;EAE7B,IAAI,CAAC,UACH,OAAO,CAAC;EAGV,KAAK,MAAM,SAAS,SAAS;GAC3B,MAAM,UAAU,SAAS,OAAO,MAAM,UAAU;GAEhD,IAAI,CAAC,SACH;GAGF,KAAK,MAAM,SAAS,SAClB,aAAa,KAAK;IAChB,KAAK;IACL,OAAO;KAAE,GAAG,MAAM;KAAO;IAAM;IAC/B,UAAU,MAAM;IAChB,GAAI,OAAO,MAAM,OAAO,QAAQ,WAC5B,EAAE,oBAAoB,KAAK,IAC3B,CAAC;GACP,CAAC;EAEL;EAEA,OAAO;CACT;CAEA,MAAM,cAAc,YAEhB,QACG,KAAK,UAAU,MAAM,OAAQ,EAC7B,KAAK,CAAC,EACN,OAAO,OAAO,EACjB,KACC,EAAE,UAAU,GAAG,cACb;EACC,KAAK;EACL,OAAO;GACL,GAAG;GACH,0BAA0B;GAC1B;EACF;EACA;CACF,EACJ;CAEF,IAAI,YAAY,OAAO,UAAU;EAC/B,MAAM,gBAAgB,OAAO,OAAO,QAAQ,IAAI;EAChD,MAAM,eAAe,gBAAgB,aAAa;EAElD,OAAO,cAAc,QADL,WAAW,aACE,GAAS,YAAY;CACpD;CAGA,MAAM,eAAe,SACnB,OAAO,OAAO,SACd,iBACA,SACF;CAIA,OAAO,cAAc,QAFL,SAAS,OAAO,OAAO,SAAS,YAAY,SAE/B,GAAS,YAAY;AACpD;AAEA,SAAS,cACP,QACA,SACA,cACA;CACA,MAAM,aAAa,CAAC,GAAG,SAAS,GAAG,YAAY;CAE/C,KAAK,YAAY,OAAO,aAAa,OAAO,WAAW;EACrD,MAAM,uBAAuB,OAAO,UAAU,oBAAoB;EAClE,IAAI,sBACF,WAAW,QAAQ,oBAAoB;CAE3C;CAEA,OACE,oBAAA,UAAA,EAAA,UACG,WAAW,KAAK,OAAO,MACtB,8BAAC,OAAD;EAAO,GAAI;EAAO,KAAK,eAAe,MAAM,IAAI,GAAG;CAAM,CAAA,CAC1D,EACD,CAAA;AAEN"} | ||
| {"version":3,"file":"Scripts.js","names":[],"sources":["../../src/Scripts.tsx"],"sourcesContent":["import { useStore } from '@tanstack/react-store'\nimport { _getAssetMatches, deepEqual } from '@tanstack/router-core'\nimport { isServer } from '@tanstack/router-core/isServer'\nimport { Asset } from './Asset'\nimport { useRouter } from './useRouter'\nimport type { RouterManagedTag } from '@tanstack/router-core'\n\ntype ScriptRenderAsset = RouterManagedTag & {\n preventScriptHoist?: boolean\n}\n\n/**\n * Render body script tags collected from route matches and SSR manifests.\n * Should be placed near the end of the document body.\n */\nexport const Scripts = () => {\n const router = useRouter()\n const nonce = router.options.ssr?.nonce\n\n const getScripts = (matches: Array<any>) => {\n matches = _getAssetMatches(matches)\n const scripts = matches\n .flatMap((match) => match.scripts ?? [])\n .filter(Boolean)\n .map(\n ({ children, ...script }) =>\n ({\n tag: 'script',\n attrs: {\n ...script,\n suppressHydrationWarning: true,\n nonce,\n },\n children,\n }) satisfies RouterManagedTag,\n ) as Array<ScriptRenderAsset>\n const manifest = router.ssr?.manifest\n\n if (!manifest) {\n return scripts\n }\n\n for (const match of matches) {\n const manifestScripts = manifest.routes[match.routeId]?.scripts\n\n if (!manifestScripts) {\n continue\n }\n\n for (const asset of manifestScripts) {\n scripts.push({\n tag: 'script',\n attrs: { ...asset.attrs, nonce },\n children: asset.children,\n ...(typeof asset.attrs?.src === 'string'\n ? { preventScriptHoist: true }\n : {}),\n })\n }\n }\n\n return scripts\n }\n\n if (isServer ?? router.isServer) {\n const activeMatches = router.stores.matches.get()\n const scripts = getScripts(activeMatches)\n return renderScripts(router, scripts)\n }\n\n // eslint-disable-next-line react-hooks/rules-of-hooks -- condition is static\n const scripts = useStore(router.stores.matches, getScripts, deepEqual)\n\n return renderScripts(router, scripts)\n}\n\nfunction renderScripts(\n router: ReturnType<typeof useRouter>,\n scripts: Array<ScriptRenderAsset>,\n) {\n if ((isServer ?? router.isServer) && router.serverSsr) {\n const serverBufferedScript = router.serverSsr.takeBufferedScripts()\n if (serverBufferedScript) {\n scripts.unshift(serverBufferedScript)\n }\n }\n\n return (\n <>\n {scripts.map((asset, i) => (\n <Asset {...asset} key={`tsr-scripts-${asset.tag}-${i}`} />\n ))}\n </>\n )\n}\n"],"mappings":";;;;;;;;;;;;AAeA,IAAa,gBAAgB;CAC3B,MAAM,SAAS,UAAU;CACzB,MAAM,QAAQ,OAAO,QAAQ,KAAK;CAElC,MAAM,cAAc,YAAwB;EAC1C,UAAU,iBAAiB,OAAO;EAClC,MAAM,UAAU,QACb,SAAS,UAAU,MAAM,WAAW,CAAC,CAAC,EACtC,OAAO,OAAO,EACd,KACE,EAAE,UAAU,GAAG,cACb;GACC,KAAK;GACL,OAAO;IACL,GAAG;IACH,0BAA0B;IAC1B;GACF;GACA;EACF,EACJ;EACF,MAAM,WAAW,OAAO,KAAK;EAE7B,IAAI,CAAC,UACH,OAAO;EAGT,KAAK,MAAM,SAAS,SAAS;GAC3B,MAAM,kBAAkB,SAAS,OAAO,MAAM,UAAU;GAExD,IAAI,CAAC,iBACH;GAGF,KAAK,MAAM,SAAS,iBAClB,QAAQ,KAAK;IACX,KAAK;IACL,OAAO;KAAE,GAAG,MAAM;KAAO;IAAM;IAC/B,UAAU,MAAM;IAChB,GAAI,OAAO,MAAM,OAAO,QAAQ,WAC5B,EAAE,oBAAoB,KAAK,IAC3B,CAAC;GACP,CAAC;EAEL;EAEA,OAAO;CACT;CAEA,IAAI,YAAY,OAAO,UAGrB,OAAO,cAAc,QADL,WADM,OAAO,OAAO,QAAQ,IACjB,CACE,CAAO;CAMtC,OAAO,cAAc,QAFL,SAAS,OAAO,OAAO,SAAS,YAAY,SAE/B,CAAO;AACtC;AAEA,SAAS,cACP,QACA,SACA;CACA,KAAK,YAAY,OAAO,aAAa,OAAO,WAAW;EACrD,MAAM,uBAAuB,OAAO,UAAU,oBAAoB;EAClE,IAAI,sBACF,QAAQ,QAAQ,oBAAoB;CAExC;CAEA,OACE,oBAAA,UAAA,EAAA,UACG,QAAQ,KAAK,OAAO,MACnB,8BAAC,OAAD;EAAO,GAAI;EAAO,KAAK,eAAe,MAAM,IAAI,GAAG;CAAM,CAAA,CAC1D,EACD,CAAA;AAEN"} |
@@ -32,5 +32,8 @@ import { createSsrStreamResponse, transformPipeableStreamWithRouter, transformReadableStreamWithRouter } from "@tanstack/router-core/ssr/server"; | ||
| if (isbot(request.headers.get("User-Agent"))) await waitForReadyOrAbort(stream.allReady, request.signal); | ||
| const responseStream = transformReadableStreamWithRouter(router, stream, { onAbort: () => stream.cancel().catch(() => {}) }); | ||
| const responseStream = transformReadableStreamWithRouter(router, stream, { | ||
| signal: request.signal, | ||
| onAbort: () => stream.cancel().catch(() => {}) | ||
| }); | ||
| return createSsrStreamResponse(router, new Response(responseStream, { | ||
| status: router.stores.statusCode.get(), | ||
| status: router._serverResult?.type === "render" ? router._serverResult.status : 200, | ||
| headers: responseHeaders | ||
@@ -91,3 +94,6 @@ })); | ||
| } | ||
| const responseStream = transformPipeableStreamWithRouter(router, reactAppPassthrough, { onAbort: abortPipeable }); | ||
| const responseStream = transformPipeableStreamWithRouter(router, reactAppPassthrough, { | ||
| signal: request.signal, | ||
| onAbort: abortPipeable | ||
| }); | ||
| responseAttached = true; | ||
@@ -99,3 +105,3 @@ if (endedBeforeAttach) reactAppPassthrough.destroy(pendingDestroyError()); | ||
| return createSsrStreamResponse(router, new Response(responseStream, { | ||
| status: router.stores.statusCode.get(), | ||
| status: router._serverResult?.type === "render" ? router._serverResult.status : 200, | ||
| headers: responseHeaders | ||
@@ -102,0 +108,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\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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"} | ||
| {"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 {\n signal: request.signal,\n onAbort: () => stream.cancel().catch(() => {}),\n },\n )\n return createSsrStreamResponse(\n router,\n new Response(responseStream as any, {\n status:\n router._serverResult?.type === 'render'\n ? router._serverResult.status\n : 200,\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 { signal: request.signal, 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:\n router._serverResult?.type === 'render'\n ? router._serverResult.status\n : 200,\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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"} |
@@ -10,3 +10,3 @@ import ReactDOMServer from "react-dom/server"; | ||
| return new Response(`<!DOCTYPE html>${html}`, { | ||
| status: router.stores.statusCode.get(), | ||
| status: router._serverResult?.type === "render" ? router._serverResult.status : 200, | ||
| headers: responseHeaders | ||
@@ -13,0 +13,0 @@ }); |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"renderRouterToString.js","names":[],"sources":["../../../src/ssr/renderRouterToString.tsx"],"sourcesContent":["import ReactDOMServer from 'react-dom/server'\nimport type { ReactNode } from 'react'\nimport type { AnyRouter } from '@tanstack/router-core'\n\nexport const renderRouterToString = async ({\n router,\n responseHeaders,\n children,\n}: {\n router: AnyRouter\n responseHeaders: Headers\n children: ReactNode\n}) => {\n try {\n let html = ReactDOMServer.renderToString(children)\n router.serverSsr!.setRenderFinished()\n\n const injectedHtml = router.serverSsr!.takeBufferedHtml()\n if (injectedHtml) {\n html = html.replace(`</body>`, () => `${injectedHtml}</body>`)\n }\n\n return new Response(`<!DOCTYPE html>${html}`, {\n status: router.stores.statusCode.get(),\n headers: responseHeaders,\n })\n } catch (error) {\n console.error('Render to string error:', error)\n return new Response('Internal Server Error', {\n status: 500,\n headers: responseHeaders,\n })\n } finally {\n router.serverSsr?.cleanup()\n }\n}\n"],"mappings":";;AAIA,IAAa,uBAAuB,OAAO,EACzC,QACA,iBACA,eAKI;CACJ,IAAI;EACF,IAAI,OAAO,eAAe,eAAe,QAAQ;EACjD,OAAO,UAAW,kBAAkB;EAEpC,MAAM,eAAe,OAAO,UAAW,iBAAiB;EACxD,IAAI,cACF,OAAO,KAAK,QAAQ,iBAAiB,GAAG,aAAa,QAAQ;EAG/D,OAAO,IAAI,SAAS,kBAAkB,QAAQ;GAC5C,QAAQ,OAAO,OAAO,WAAW,IAAI;GACrC,SAAS;EACX,CAAC;CACH,SAAS,OAAO;EACd,QAAQ,MAAM,2BAA2B,KAAK;EAC9C,OAAO,IAAI,SAAS,yBAAyB;GAC3C,QAAQ;GACR,SAAS;EACX,CAAC;CACH,UAAU;EACR,OAAO,WAAW,QAAQ;CAC5B;AACF"} | ||
| {"version":3,"file":"renderRouterToString.js","names":[],"sources":["../../../src/ssr/renderRouterToString.tsx"],"sourcesContent":["import ReactDOMServer from 'react-dom/server'\nimport type { ReactNode } from 'react'\nimport type { AnyRouter } from '@tanstack/router-core'\n\nexport const renderRouterToString = async ({\n router,\n responseHeaders,\n children,\n}: {\n router: AnyRouter\n responseHeaders: Headers\n children: ReactNode\n}) => {\n try {\n let html = ReactDOMServer.renderToString(children)\n router.serverSsr!.setRenderFinished()\n\n const injectedHtml = router.serverSsr!.takeBufferedHtml()\n if (injectedHtml) {\n html = html.replace(`</body>`, () => `${injectedHtml}</body>`)\n }\n\n return new Response(`<!DOCTYPE html>${html}`, {\n status:\n router._serverResult?.type === 'render'\n ? router._serverResult.status\n : 200,\n headers: responseHeaders,\n })\n } catch (error) {\n console.error('Render to string error:', error)\n return new Response('Internal Server Error', {\n status: 500,\n headers: responseHeaders,\n })\n } finally {\n router.serverSsr?.cleanup()\n }\n}\n"],"mappings":";;AAIA,IAAa,uBAAuB,OAAO,EACzC,QACA,iBACA,eAKI;CACJ,IAAI;EACF,IAAI,OAAO,eAAe,eAAe,QAAQ;EACjD,OAAO,UAAW,kBAAkB;EAEpC,MAAM,eAAe,OAAO,UAAW,iBAAiB;EACxD,IAAI,cACF,OAAO,KAAK,QAAQ,iBAAiB,GAAG,aAAa,QAAQ;EAG/D,OAAO,IAAI,SAAS,kBAAkB,QAAQ;GAC5C,QACE,OAAO,eAAe,SAAS,WAC3B,OAAO,cAAc,SACrB;GACN,SAAS;EACX,CAAC;CACH,SAAS,OAAO;EACd,QAAQ,MAAM,2BAA2B,KAAK;EAC9C,OAAO,IAAI,SAAS,yBAAyB;GAC3C,QAAQ;GACR,SAAS;EACX,CAAC;CACH,UAAU;EACR,OAAO,WAAW,QAAQ;CAC5B;AACF"} |
@@ -8,4 +8,3 @@ import { Await } from "../awaited.js"; | ||
| function RouterClient(props) { | ||
| if (!hydrationPromise) if (!props.router.stores.matchesId.get().length) hydrationPromise = hydrate(props.router); | ||
| else hydrationPromise = Promise.resolve(); | ||
| hydrationPromise ??= hydrate(props.router).finally(() => window.$_TSR.h()); | ||
| return /* @__PURE__ */ jsx(Await, { | ||
@@ -12,0 +11,0 @@ promise: hydrationPromise, |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"RouterClient.js","names":[],"sources":["../../../src/ssr/RouterClient.tsx"],"sourcesContent":["import { hydrate } from '@tanstack/router-core/ssr/client'\nimport { Await } from '../awaited'\nimport { RouterProvider } from '../RouterProvider'\nimport type { AnyRouter } from '@tanstack/router-core'\n\nlet hydrationPromise: Promise<void | Array<Array<void>>> | undefined\n\nexport function RouterClient(props: { router: AnyRouter }) {\n if (!hydrationPromise) {\n if (!props.router.stores.matchesId.get().length) {\n hydrationPromise = hydrate(props.router)\n } else {\n hydrationPromise = Promise.resolve()\n }\n }\n return (\n <Await\n promise={hydrationPromise}\n children={() => <RouterProvider router={props.router} />}\n />\n )\n}\n"],"mappings":";;;;;AAKA,IAAI;AAEJ,SAAgB,aAAa,OAA8B;CACzD,IAAI,CAAC,kBACH,IAAI,CAAC,MAAM,OAAO,OAAO,UAAU,IAAI,EAAE,QACvC,mBAAmB,QAAQ,MAAM,MAAM;MAEvC,mBAAmB,QAAQ,QAAQ;CAGvC,OACE,oBAAC,OAAD;EACE,SAAS;EACT,gBAAgB,oBAAC,gBAAD,EAAgB,QAAQ,MAAM,OAAS,CAAA;CACxD,CAAA;AAEL"} | ||
| {"version":3,"file":"RouterClient.js","names":[],"sources":["../../../src/ssr/RouterClient.tsx"],"sourcesContent":["import { hydrate } from '@tanstack/router-core/ssr/client'\nimport { Await } from '../awaited'\nimport { RouterProvider } from '../RouterProvider'\nimport type { AnyRouter } from '@tanstack/router-core'\n\nlet hydrationPromise: Promise<void> | undefined\n\nexport function RouterClient(props: { router: AnyRouter }) {\n hydrationPromise ??= hydrate(props.router).finally(() => window.$_TSR!.h())\n\n return (\n <Await\n promise={hydrationPromise}\n children={() => <RouterProvider router={props.router} />}\n />\n )\n}\n"],"mappings":";;;;;AAKA,IAAI;AAEJ,SAAgB,aAAa,OAA8B;CACzD,qBAAqB,QAAQ,MAAM,MAAM,EAAE,cAAc,OAAO,MAAO,EAAE,CAAC;CAE1E,OACE,oBAAC,OAAD;EACE,SAAS;EACT,gBAAgB,oBAAC,gBAAD,EAAgB,QAAQ,MAAM,OAAS,CAAA;CACxD,CAAA;AAEL"} |
+55
-79
| "use client"; | ||
| import { useLayoutEffect, usePrevious } from "./utils.js"; | ||
| import { useLayoutEffect } from "./utils.js"; | ||
| import { useRouter } from "./useRouter.js"; | ||
| import { getLocationChangeInfo, trimPathRight } from "@tanstack/router-core"; | ||
| import * as React$1 from "react"; | ||
| import { batch, useStore } from "@tanstack/react-store"; | ||
| //#region src/Transitioner.tsx | ||
| function Transitioner() { | ||
| const router = useRouter(); | ||
| const mountLoadForRouter = React$1.useRef({ | ||
| router, | ||
| mounted: false | ||
| const acknowledgement = React$1.useRef(void 0); | ||
| const mounted = process.env.NODE_ENV !== "production" ? React$1.useRef(false) : void 0; | ||
| router._rendered = (matches) => { | ||
| const current = acknowledgement.current; | ||
| if (current?.[0].length === matches.length && current[0].every((match, index) => match.id === matches[index].id && match.abortController === matches[index].abortController && match.status === matches[index].status)) { | ||
| acknowledgement.current = void 0; | ||
| current[1](true); | ||
| } | ||
| }; | ||
| if (process.env.NODE_ENV === "production") router.startTransition = (fn, expected, urgent) => new Promise((resolve) => { | ||
| acknowledgement.current?.[1](false); | ||
| acknowledgement.current = [expected, resolve]; | ||
| if (urgent) fn(); | ||
| else React$1.startTransition(fn); | ||
| }); | ||
| const [isTransitioning, setIsTransitioning] = React$1.useState(false); | ||
| const isLoading = useStore(router.stores.isLoading, (value) => value); | ||
| const hasPending = useStore(router.stores.hasPending, (value) => value); | ||
| const previousIsLoading = usePrevious(isLoading); | ||
| const isAnyPending = isLoading || isTransitioning || hasPending; | ||
| const previousIsAnyPending = usePrevious(isAnyPending); | ||
| const isPagePending = isLoading || hasPending; | ||
| const previousIsPagePending = usePrevious(isPagePending); | ||
| router.startTransition = (fn) => { | ||
| setIsTransitioning(true); | ||
| React$1.startTransition(() => { | ||
| fn(); | ||
| setIsTransitioning(false); | ||
| else { | ||
| router.startTransition = (fn, expected, urgent) => new Promise((resolve, reject) => { | ||
| acknowledgement.current?.[1](false); | ||
| const next = [expected, resolve]; | ||
| acknowledgement.current = next; | ||
| try { | ||
| if (urgent) fn(); | ||
| else React$1.startTransition(fn); | ||
| } catch (cause) { | ||
| if (acknowledgement.current === next) acknowledgement.current = void 0; | ||
| reject(cause); | ||
| } | ||
| }); | ||
| }; | ||
| React$1.useEffect(() => { | ||
| router._cancelTransition = () => { | ||
| const current = acknowledgement.current; | ||
| acknowledgement.current = void 0; | ||
| current?.[1](false); | ||
| }; | ||
| } | ||
| useLayoutEffect(() => { | ||
| const unsub = router.history.subscribe(router.load); | ||
| if (mounted?.current) return unsub; | ||
| if (mounted) mounted.current = true; | ||
| router.updateLatestLocation(); | ||
| const location = router.latestLocation; | ||
| const nextLocation = router.buildLocation({ | ||
| to: router.latestLocation.pathname, | ||
| to: location.pathname, | ||
| search: true, | ||
@@ -39,62 +57,20 @@ params: true, | ||
| }); | ||
| if (trimPathRight(router.latestLocation.publicHref) !== trimPathRight(nextLocation.publicHref)) router.commitLocation({ | ||
| ...nextLocation, | ||
| replace: true | ||
| }); | ||
| return () => { | ||
| unsub(); | ||
| }; | ||
| }, [router, router.history]); | ||
| useLayoutEffect(() => { | ||
| if (typeof window !== "undefined" && router.ssr || mountLoadForRouter.current.router === router && mountLoadForRouter.current.mounted) return; | ||
| mountLoadForRouter.current = { | ||
| router, | ||
| mounted: true | ||
| }; | ||
| const tryLoad = async () => { | ||
| try { | ||
| await router.load(); | ||
| } catch (err) { | ||
| console.error(err); | ||
| } | ||
| }; | ||
| tryLoad(); | ||
| }, [router]); | ||
| useLayoutEffect(() => { | ||
| if (previousIsLoading && !isLoading) router.emit({ | ||
| type: "onLoad", | ||
| ...getLocationChangeInfo(router.stores.location.get(), router.stores.resolvedLocation.get()) | ||
| }); | ||
| }, [ | ||
| previousIsLoading, | ||
| router, | ||
| isLoading | ||
| ]); | ||
| useLayoutEffect(() => { | ||
| if (previousIsPagePending && !isPagePending) router.emit({ | ||
| type: "onBeforeRouteMount", | ||
| ...getLocationChangeInfo(router.stores.location.get(), router.stores.resolvedLocation.get()) | ||
| }); | ||
| }, [ | ||
| isPagePending, | ||
| previousIsPagePending, | ||
| router | ||
| ]); | ||
| useLayoutEffect(() => { | ||
| if (previousIsAnyPending && !isAnyPending) { | ||
| const changeInfo = getLocationChangeInfo(router.stores.location.get(), router.stores.resolvedLocation.get()); | ||
| router.emit({ | ||
| type: "onResolved", | ||
| ...changeInfo | ||
| if (trimPathRight(location.publicHref) !== trimPathRight(nextLocation.publicHref)) { | ||
| router.commitLocation({ | ||
| ...nextLocation, | ||
| replace: true, | ||
| ignoreBlocker: true | ||
| }); | ||
| batch(() => { | ||
| router.stores.status.set("idle"); | ||
| router.stores.resolvedLocation.set(router.stores.location.get()); | ||
| return unsub; | ||
| } | ||
| const resolvedLocation = router.stores.resolvedLocation.get(); | ||
| if (resolvedLocation?.href === location.href && resolvedLocation.state.__TSR_key === location.state.__TSR_key) acknowledgement.current = [router.stores.matches.get(), (rendered) => { | ||
| if (rendered) router.emit({ | ||
| type: "onRendered", | ||
| ...getLocationChangeInfo(resolvedLocation, resolvedLocation) | ||
| }); | ||
| } | ||
| }, [ | ||
| isAnyPending, | ||
| previousIsAnyPending, | ||
| router | ||
| ]); | ||
| }]; | ||
| else if (!router._tx) router.load().catch(console.error); | ||
| return unsub; | ||
| }, [router, router.history]); | ||
| return null; | ||
@@ -101,0 +77,0 @@ } |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"Transitioner.js","names":[],"sources":["../../src/Transitioner.tsx"],"sourcesContent":["'use client'\n\nimport * as React from 'react'\nimport { batch, useStore } from '@tanstack/react-store'\nimport { getLocationChangeInfo, trimPathRight } from '@tanstack/router-core'\nimport { useLayoutEffect, usePrevious } from './utils'\nimport { useRouter } from './useRouter'\n\nexport function Transitioner() {\n const router = useRouter()\n const mountLoadForRouter = React.useRef({ router, mounted: false })\n\n const [isTransitioning, setIsTransitioning] = React.useState(false)\n // Track pending state changes\n const isLoading = useStore(router.stores.isLoading, (value) => value)\n const hasPending = useStore(router.stores.hasPending, (value) => value)\n\n const previousIsLoading = usePrevious(isLoading)\n\n const isAnyPending = isLoading || isTransitioning || hasPending\n const previousIsAnyPending = usePrevious(isAnyPending)\n\n const isPagePending = isLoading || hasPending\n const previousIsPagePending = usePrevious(isPagePending)\n\n router.startTransition = (fn: () => void) => {\n setIsTransitioning(true)\n React.startTransition(() => {\n fn()\n setIsTransitioning(false)\n })\n }\n\n // Subscribe to location changes\n // and try to load the new location\n React.useEffect(() => {\n const unsub = router.history.subscribe(router.load)\n\n const nextLocation = router.buildLocation({\n to: router.latestLocation.pathname,\n search: true,\n params: true,\n hash: true,\n state: true,\n _includeValidateSearch: true,\n })\n\n // Check if the current URL matches the canonical form.\n // Compare publicHref (browser-facing URL) for consistency with\n // the server-side redirect check in router.beforeLoad.\n if (\n trimPathRight(router.latestLocation.publicHref) !==\n trimPathRight(nextLocation.publicHref)\n ) {\n router.commitLocation({ ...nextLocation, replace: true })\n }\n\n return () => {\n unsub()\n }\n }, [router, router.history])\n\n // Try to load the initial location\n useLayoutEffect(() => {\n if (\n // if we are hydrating from SSR, loading is triggered in ssr-client\n (typeof window !== 'undefined' && router.ssr) ||\n (mountLoadForRouter.current.router === router &&\n mountLoadForRouter.current.mounted)\n ) {\n return\n }\n mountLoadForRouter.current = { router, mounted: true }\n\n const tryLoad = async () => {\n try {\n await router.load()\n } catch (err) {\n console.error(err)\n }\n }\n\n tryLoad()\n }, [router])\n\n useLayoutEffect(() => {\n // The router was loading and now it's not\n if (previousIsLoading && !isLoading) {\n router.emit({\n type: 'onLoad', // When the new URL has committed, when the new matches have been loaded into state.matches\n ...getLocationChangeInfo(\n router.stores.location.get(),\n router.stores.resolvedLocation.get(),\n ),\n })\n }\n }, [previousIsLoading, router, isLoading])\n\n useLayoutEffect(() => {\n // emit onBeforeRouteMount\n if (previousIsPagePending && !isPagePending) {\n router.emit({\n type: 'onBeforeRouteMount',\n ...getLocationChangeInfo(\n router.stores.location.get(),\n router.stores.resolvedLocation.get(),\n ),\n })\n }\n }, [isPagePending, previousIsPagePending, router])\n\n useLayoutEffect(() => {\n if (previousIsAnyPending && !isAnyPending) {\n const changeInfo = getLocationChangeInfo(\n router.stores.location.get(),\n router.stores.resolvedLocation.get(),\n )\n router.emit({\n type: 'onResolved',\n ...changeInfo,\n })\n\n batch(() => {\n router.stores.status.set('idle')\n router.stores.resolvedLocation.set(router.stores.location.get())\n })\n }\n }, [isAnyPending, previousIsAnyPending, router])\n\n return null\n}\n"],"mappings":";;;;;;;AAQA,SAAgB,eAAe;CAC7B,MAAM,SAAS,UAAU;CACzB,MAAM,qBAAqB,QAAM,OAAO;EAAE;EAAQ,SAAS;CAAM,CAAC;CAElE,MAAM,CAAC,iBAAiB,sBAAsB,QAAM,SAAS,KAAK;CAElE,MAAM,YAAY,SAAS,OAAO,OAAO,YAAY,UAAU,KAAK;CACpE,MAAM,aAAa,SAAS,OAAO,OAAO,aAAa,UAAU,KAAK;CAEtE,MAAM,oBAAoB,YAAY,SAAS;CAE/C,MAAM,eAAe,aAAa,mBAAmB;CACrD,MAAM,uBAAuB,YAAY,YAAY;CAErD,MAAM,gBAAgB,aAAa;CACnC,MAAM,wBAAwB,YAAY,aAAa;CAEvD,OAAO,mBAAmB,OAAmB;EAC3C,mBAAmB,IAAI;EACvB,QAAM,sBAAsB;GAC1B,GAAG;GACH,mBAAmB,KAAK;EAC1B,CAAC;CACH;CAIA,QAAM,gBAAgB;EACpB,MAAM,QAAQ,OAAO,QAAQ,UAAU,OAAO,IAAI;EAElD,MAAM,eAAe,OAAO,cAAc;GACxC,IAAI,OAAO,eAAe;GAC1B,QAAQ;GACR,QAAQ;GACR,MAAM;GACN,OAAO;GACP,wBAAwB;EAC1B,CAAC;EAKD,IACE,cAAc,OAAO,eAAe,UAAU,MAC9C,cAAc,aAAa,UAAU,GAErC,OAAO,eAAe;GAAE,GAAG;GAAc,SAAS;EAAK,CAAC;EAG1D,aAAa;GACX,MAAM;EACR;CACF,GAAG,CAAC,QAAQ,OAAO,OAAO,CAAC;CAG3B,sBAAsB;EACpB,IAEG,OAAO,WAAW,eAAe,OAAO,OACxC,mBAAmB,QAAQ,WAAW,UACrC,mBAAmB,QAAQ,SAE7B;EAEF,mBAAmB,UAAU;GAAE;GAAQ,SAAS;EAAK;EAErD,MAAM,UAAU,YAAY;GAC1B,IAAI;IACF,MAAM,OAAO,KAAK;GACpB,SAAS,KAAK;IACZ,QAAQ,MAAM,GAAG;GACnB;EACF;EAEA,QAAQ;CACV,GAAG,CAAC,MAAM,CAAC;CAEX,sBAAsB;EAEpB,IAAI,qBAAqB,CAAC,WACxB,OAAO,KAAK;GACV,MAAM;GACN,GAAG,sBACD,OAAO,OAAO,SAAS,IAAI,GAC3B,OAAO,OAAO,iBAAiB,IAAI,CACrC;EACF,CAAC;CAEL,GAAG;EAAC;EAAmB;EAAQ;CAAS,CAAC;CAEzC,sBAAsB;EAEpB,IAAI,yBAAyB,CAAC,eAC5B,OAAO,KAAK;GACV,MAAM;GACN,GAAG,sBACD,OAAO,OAAO,SAAS,IAAI,GAC3B,OAAO,OAAO,iBAAiB,IAAI,CACrC;EACF,CAAC;CAEL,GAAG;EAAC;EAAe;EAAuB;CAAM,CAAC;CAEjD,sBAAsB;EACpB,IAAI,wBAAwB,CAAC,cAAc;GACzC,MAAM,aAAa,sBACjB,OAAO,OAAO,SAAS,IAAI,GAC3B,OAAO,OAAO,iBAAiB,IAAI,CACrC;GACA,OAAO,KAAK;IACV,MAAM;IACN,GAAG;GACL,CAAC;GAED,YAAY;IACV,OAAO,OAAO,OAAO,IAAI,MAAM;IAC/B,OAAO,OAAO,iBAAiB,IAAI,OAAO,OAAO,SAAS,IAAI,CAAC;GACjE,CAAC;EACH;CACF,GAAG;EAAC;EAAc;EAAsB;CAAM,CAAC;CAE/C,OAAO;AACT"} | ||
| {"version":3,"file":"Transitioner.js","names":[],"sources":["../../src/Transitioner.tsx"],"sourcesContent":["'use client'\n\nimport * as React from 'react'\nimport { getLocationChangeInfo, trimPathRight } from '@tanstack/router-core'\nimport { useLayoutEffect } from './utils'\nimport { useRouter } from './useRouter'\nimport type { AnyRouteMatch } from '@tanstack/router-core'\n\nexport function Transitioner() {\n const router = useRouter()\n const acknowledgement = React.useRef<\n [Array<AnyRouteMatch>, (rendered: boolean) => void] | undefined\n >(undefined)\n const mounted =\n process.env.NODE_ENV !== 'production'\n ? // eslint-disable-next-line react-hooks/rules-of-hooks\n React.useRef(false)\n : undefined\n\n // `<Transitioner>` precedes `<MatchesInner>`, so install the render\n // acknowledgement before the latter can publish a rendered lane.\n router._rendered = (matches) => {\n const current = acknowledgement.current\n if (\n current?.[0].length === matches.length &&\n current[0].every(\n (match, index) =>\n match.id === matches[index]!.id &&\n match.abortController === matches[index]!.abortController &&\n match.status === matches[index]!.status,\n )\n ) {\n acknowledgement.current = undefined\n current[1](true)\n }\n }\n if (process.env.NODE_ENV === 'production') {\n router.startTransition = (fn, expected, urgent) =>\n new Promise((resolve) => {\n acknowledgement.current?.[1](false)\n acknowledgement.current = [expected, resolve]\n if (urgent) {\n fn()\n } else {\n React.startTransition(fn)\n }\n })\n } else {\n router.startTransition = (fn, expected, urgent) =>\n new Promise((resolve, reject) => {\n acknowledgement.current?.[1](false)\n const next: NonNullable<typeof acknowledgement.current> = [\n expected,\n resolve,\n ]\n acknowledgement.current = next\n try {\n if (urgent) {\n fn()\n } else {\n React.startTransition(fn)\n }\n } catch (cause) {\n if (acknowledgement.current === next) {\n acknowledgement.current = undefined\n }\n reject(cause)\n }\n })\n ;(\n router as typeof router & { _cancelTransition?: () => void }\n )._cancelTransition = () => {\n const current = acknowledgement.current\n acknowledgement.current = undefined\n current?.[1](false)\n }\n }\n\n // Subscribe before canonicalizing so the initial URL has exactly one load.\n useLayoutEffect(() => {\n const unsub = router.history.subscribe(router.load)\n\n if (mounted?.current) {\n return unsub\n }\n if (mounted) {\n mounted.current = true\n }\n\n router.updateLatestLocation()\n const location = router.latestLocation\n const nextLocation = router.buildLocation({\n to: location.pathname,\n search: true,\n params: true,\n hash: true,\n state: true,\n _includeValidateSearch: true,\n })\n\n // Check if the current URL matches the canonical form.\n // Compare publicHref (browser-facing URL) consistently with server\n // canonicalization.\n if (\n trimPathRight(location.publicHref) !==\n trimPathRight(nextLocation.publicHref)\n ) {\n router.commitLocation({\n ...nextLocation,\n replace: true,\n ignoreBlocker: true,\n })\n return unsub\n }\n\n const resolvedLocation = router.stores.resolvedLocation.get()\n if (\n resolvedLocation?.href === location.href &&\n resolvedLocation.state.__TSR_key === location.state.__TSR_key\n ) {\n acknowledgement.current = [\n router.stores.matches.get(),\n (rendered) => {\n if (rendered) {\n router.emit({\n type: 'onRendered',\n ...getLocationChangeInfo(resolvedLocation, resolvedLocation),\n })\n }\n },\n ]\n } else if (!router._tx) {\n router.load().catch(console.error)\n }\n\n return unsub\n // `mounted` exists only in development and is a stable ref when present.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [router, router.history])\n\n return null\n}\n"],"mappings":";;;;;;AAQA,SAAgB,eAAe;CAC7B,MAAM,SAAS,UAAU;CACzB,MAAM,kBAAkB,QAAM,OAE5B,KAAA,CAAS;CACX,MAAM,UAAA,QAAA,IAAA,aACqB,eAErB,QAAM,OAAO,KAAK,IAClB,KAAA;CAIN,OAAO,aAAa,YAAY;EAC9B,MAAM,UAAU,gBAAgB;EAChC,IACE,UAAU,GAAG,WAAW,QAAQ,UAChC,QAAQ,GAAG,OACR,OAAO,UACN,MAAM,OAAO,QAAQ,OAAQ,MAC7B,MAAM,oBAAoB,QAAQ,OAAQ,mBAC1C,MAAM,WAAW,QAAQ,OAAQ,MACrC,GACA;GACA,gBAAgB,UAAU,KAAA;GAC1B,QAAQ,GAAG,IAAI;EACjB;CACF;CACA,IAAA,QAAA,IAAA,aAA6B,cAC3B,OAAO,mBAAmB,IAAI,UAAU,WACtC,IAAI,SAAS,YAAY;EACvB,gBAAgB,UAAU,GAAG,KAAK;EAClC,gBAAgB,UAAU,CAAC,UAAU,OAAO;EAC5C,IAAI,QACF,GAAG;OAEH,QAAM,gBAAgB,EAAE;CAE5B,CAAC;MACE;EACL,OAAO,mBAAmB,IAAI,UAAU,WACtC,IAAI,SAAS,SAAS,WAAW;GAC/B,gBAAgB,UAAU,GAAG,KAAK;GAClC,MAAM,OAAoD,CACxD,UACA,OACF;GACA,gBAAgB,UAAU;GAC1B,IAAI;IACF,IAAI,QACF,GAAG;SAEH,QAAM,gBAAgB,EAAE;GAE5B,SAAS,OAAO;IACd,IAAI,gBAAgB,YAAY,MAC9B,gBAAgB,UAAU,KAAA;IAE5B,OAAO,KAAK;GACd;EACF,CAAC;EACF,OAEC,0BAA0B;GAC1B,MAAM,UAAU,gBAAgB;GAChC,gBAAgB,UAAU,KAAA;GAC1B,UAAU,GAAG,KAAK;EACpB;CACF;CAGA,sBAAsB;EACpB,MAAM,QAAQ,OAAO,QAAQ,UAAU,OAAO,IAAI;EAElD,IAAI,SAAS,SACX,OAAO;EAET,IAAI,SACF,QAAQ,UAAU;EAGpB,OAAO,qBAAqB;EAC5B,MAAM,WAAW,OAAO;EACxB,MAAM,eAAe,OAAO,cAAc;GACxC,IAAI,SAAS;GACb,QAAQ;GACR,QAAQ;GACR,MAAM;GACN,OAAO;GACP,wBAAwB;EAC1B,CAAC;EAKD,IACE,cAAc,SAAS,UAAU,MACjC,cAAc,aAAa,UAAU,GACrC;GACA,OAAO,eAAe;IACpB,GAAG;IACH,SAAS;IACT,eAAe;GACjB,CAAC;GACD,OAAO;EACT;EAEA,MAAM,mBAAmB,OAAO,OAAO,iBAAiB,IAAI;EAC5D,IACE,kBAAkB,SAAS,SAAS,QACpC,iBAAiB,MAAM,cAAc,SAAS,MAAM,WAEpD,gBAAgB,UAAU,CACxB,OAAO,OAAO,QAAQ,IAAI,IACzB,aAAa;GACZ,IAAI,UACF,OAAO,KAAK;IACV,MAAM;IACN,GAAG,sBAAsB,kBAAkB,gBAAgB;GAC7D,CAAC;EAEL,CACF;OACK,IAAI,CAAC,OAAO,KACjB,OAAO,KAAK,EAAE,MAAM,QAAQ,KAAK;EAGnC,OAAO;CAGT,GAAG,CAAC,QAAQ,OAAO,OAAO,CAAC;CAE3B,OAAO;AACT"} |
| import { useRouter } from "./useRouter.js"; | ||
| import { isServer } from "@tanstack/router-core/isServer"; | ||
| import { useStore } from "@tanstack/react-store"; | ||
| import { isServer } from "@tanstack/router-core/isServer"; | ||
| //#region src/useCanGoBack.ts | ||
@@ -5,0 +5,0 @@ function useCanGoBack() { |
| "use client"; | ||
| import { useRouter } from "./useRouter.js"; | ||
| import { useStructuralSharing } from "./useMatch.js"; | ||
| import { isServer } from "@tanstack/router-core/isServer"; | ||
| import { useStore } from "@tanstack/react-store"; | ||
| import { isServer } from "@tanstack/router-core/isServer"; | ||
| //#region src/useLocation.tsx | ||
@@ -7,0 +7,0 @@ /** |
+8
-12
@@ -6,11 +6,6 @@ "use client"; | ||
| import * as React$1 from "react"; | ||
| import { isServer } from "@tanstack/router-core/isServer"; | ||
| import { useStore } from "@tanstack/react-store"; | ||
| import { isServer } from "@tanstack/router-core/isServer"; | ||
| //#region src/useMatch.tsx | ||
| var dummyStore = { | ||
| get() {}, | ||
| subscribe() { | ||
| return { unsubscribe() {} }; | ||
| } | ||
| }; | ||
| var dummyMatch = {}; | ||
| function useStructuralSharing(opts, router) { | ||
@@ -30,6 +25,7 @@ const previousResult = React$1.useRef(); | ||
| const router = useRouter(); | ||
| const nearestMatchId = React$1.useContext(opts.from ? dummyMatchContext : matchContext); | ||
| const matchStore = opts.from ? router.stores.getRouteMatchStore(opts.from) : router.stores.matchStores.get(nearestMatchId); | ||
| const nearestRouteId = React$1.useContext(opts.from ? dummyMatchContext : matchContext); | ||
| const routeId = opts.from ?? nearestRouteId; | ||
| const matchStore = router.stores.getMatchStore(routeId); | ||
| if (isServer ?? router.isServer) { | ||
| const match = matchStore?.get(); | ||
| const match = matchStore.get(); | ||
| if (!match) { | ||
@@ -45,4 +41,4 @@ if (opts.shouldThrow ?? true) { | ||
| const selector = useStructuralSharing(opts, router); | ||
| const matchSelection = useStore(matchStore ?? dummyStore, (match) => match ? selector(match) : dummyStore); | ||
| if (matchSelection !== dummyStore) return matchSelection; | ||
| const matchSelection = useStore(matchStore, (match) => match ? selector(match) : dummyMatch); | ||
| if (matchSelection !== dummyMatch) return matchSelection; | ||
| if (opts.shouldThrow ?? true) { | ||
@@ -49,0 +45,0 @@ 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!"}`); |
@@ -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() {},\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"} | ||
| {"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 dummyMatch = {}\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 nearestRouteId = React.useContext(\n opts.from ? dummyMatchContext : matchContext,\n )\n\n const routeId = opts.from ?? nearestRouteId\n const matchStore = router.stores.getMatchStore(routeId!)\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, (match) =>\n match ? selector(match as any) : dummyMatch,\n )\n\n if (matchSelection !== dummyMatch) {\n return matchSelection as any\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,CAAC;AAEpB,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,UAAU,KAAK,QAAQ;CAC7B,MAAM,aAAa,OAAO,OAAO,cAAc,OAAQ;CAEvD,IAAI,YAAY,OAAO,UAAU;EAC/B,MAAM,QAAQ,WAAW,IAAI;EAC7B,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,aAAa,UAC3C,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 { useStructuralSharing } from "./useMatch.js"; | ||
| import { isServer } from "@tanstack/router-core/isServer"; | ||
| import { useStore } from "@tanstack/react-store"; | ||
| import { isServer } from "@tanstack/router-core/isServer"; | ||
| //#region src/useRouterState.tsx | ||
@@ -7,0 +7,0 @@ /** |
@@ -8,3 +8,3 @@ import * as React from 'react'; | ||
| export declare function useStableCallback<T extends (...args: Array<any>) => any>(fn: T): T; | ||
| export declare const useLayoutEffect: typeof React.useLayoutEffect; | ||
| export declare const useLayoutEffect: typeof React.useEffect; | ||
| /** | ||
@@ -11,0 +11,0 @@ * Taken from https://www.developerway.com/posts/implementing-advanced-use-previous-hook#part3 |
+3
-17
| "use client"; | ||
| import * as React$1 from "react"; | ||
| import { isServer } from "@tanstack/router-core/isServer"; | ||
| /** | ||
@@ -8,19 +9,4 @@ * React.use if available (React 19+), undefined otherwise. | ||
| var reactUse = React$1["use"]; | ||
| var useLayoutEffect = typeof window !== "undefined" ? React$1.useLayoutEffect : React$1.useEffect; | ||
| var useLayoutEffect = isServer ?? typeof window === "undefined" ? React$1.useEffect : React$1.useLayoutEffect; | ||
| /** | ||
| * Taken from https://www.developerway.com/posts/implementing-advanced-use-previous-hook#part3 | ||
| */ | ||
| function usePrevious(value) { | ||
| const ref = React$1.useRef({ | ||
| value, | ||
| prev: null | ||
| }); | ||
| const current = ref.current.value; | ||
| if (value !== current) ref.current = { | ||
| value, | ||
| prev: current | ||
| }; | ||
| return ref.current.prev; | ||
| } | ||
| /** | ||
| * React hook to wrap `IntersectionObserver`. | ||
@@ -86,4 +72,4 @@ * | ||
| //#endregion | ||
| export { reactUse, useForwardedRef, useIntersectionObserver, useLayoutEffect, usePrevious }; | ||
| export { reactUse, useForwardedRef, useIntersectionObserver, useLayoutEffect }; | ||
| //# sourceMappingURL=utils.js.map |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"utils.js","names":[],"sources":["../../src/utils.ts"],"sourcesContent":["'use client'\nimport * as React from 'react'\n\n// Safe version of React.use() that will not cause compilation errors against\n// React 18 with Webpack, which statically analyzes imports and fails when it\n// sees React.use referenced (since 'use' is not exported from React 18).\n// This uses a dynamic string lookup to avoid the static analysis.\n// eslint-disable-next-line prefer-const -- Must be `let` to prevent bundler constant-folding\nlet REACT_USE = 'use'\n\n/**\n * React.use if available (React 19+), undefined otherwise.\n * Use dynamic lookup to avoid Webpack compilation errors with React 18.\n */\nexport const reactUse:\n | (<T>(usable: Promise<T> | React.Context<T>) => T)\n | undefined = (React as any)[REACT_USE]\n\nexport function useStableCallback<T extends (...args: Array<any>) => any>(\n fn: T,\n): T {\n const fnRef = React.useRef(fn)\n fnRef.current = fn\n\n const ref = React.useRef((...args: Array<any>) => fnRef.current(...args))\n return ref.current as T\n}\n\nexport const useLayoutEffect =\n typeof window !== 'undefined' ? React.useLayoutEffect : React.useEffect\n\n/**\n * Taken from https://www.developerway.com/posts/implementing-advanced-use-previous-hook#part3\n */\nexport function usePrevious<T>(value: T): T | null {\n // initialise the ref with previous and current values\n const ref = React.useRef<{ value: T; prev: T | null }>({\n value: value,\n prev: null,\n })\n\n const current = ref.current.value\n\n // if the value passed into hook doesn't match what we store as \"current\"\n // move the \"current\" to the \"previous\"\n // and store the passed value as \"current\"\n if (value !== current) {\n ref.current = {\n value: value,\n prev: current,\n }\n }\n\n // return the previous value only\n return ref.current.prev\n}\n\n/**\n * React hook to wrap `IntersectionObserver`.\n *\n * This hook will create an `IntersectionObserver` and observe the ref passed to it.\n *\n * When the intersection changes, the callback will be called with the `IntersectionObserverEntry`.\n *\n * @param ref - The ref to observe\n * @param intersectionObserverOptions - The options to pass to the IntersectionObserver\n * @param options - The options to pass to the hook\n * @param callback - The callback to call when the intersection changes\n * @returns The IntersectionObserver instance\n * @example\n * ```tsx\n * const MyComponent = () => {\n * const ref = React.useRef<HTMLDivElement>(null)\n * useIntersectionObserver(\n * ref,\n * (entry) => { doSomething(entry) },\n * { rootMargin: '10px' },\n * { disabled: false }\n * )\n * return <div ref={ref} />\n * ```\n */\nexport function useIntersectionObserver<T extends Element>(\n ref: React.RefObject<T | null>,\n callback: (entry: IntersectionObserverEntry | undefined) => void,\n intersectionObserverOptions: IntersectionObserverInit = {},\n options: { disabled?: boolean } = {},\n) {\n React.useEffect(() => {\n if (\n !ref.current ||\n options.disabled ||\n typeof IntersectionObserver !== 'function'\n ) {\n return\n }\n\n const observer = new IntersectionObserver(([entry]) => {\n callback(entry)\n }, intersectionObserverOptions)\n\n observer.observe(ref.current)\n\n return () => {\n observer.disconnect()\n }\n }, [callback, intersectionObserverOptions, options.disabled, ref])\n}\n\n/**\n * React hook to take a `React.ForwardedRef` and returns a `ref` that can be used on a DOM element.\n *\n * @param ref - The forwarded ref\n * @returns The inner ref returned by `useRef`\n * @example\n * ```tsx\n * const MyComponent = React.forwardRef((props, ref) => {\n * const innerRef = useForwardedRef(ref)\n * return <div ref={innerRef} />\n * })\n * ```\n */\nexport function useForwardedRef<T>(ref?: React.ForwardedRef<T>) {\n const innerRef = React.useRef<T>(null)\n React.useImperativeHandle(ref, () => innerRef.current!, [])\n return innerRef\n}\n"],"mappings":";;;;;;AAcA,IAAa,WAEI,QAAc;AAY/B,IAAa,kBACX,OAAO,WAAW,cAAc,QAAM,kBAAkB,QAAM;;;;AAKhE,SAAgB,YAAe,OAAoB;CAEjD,MAAM,MAAM,QAAM,OAAqC;EAC9C;EACP,MAAM;CACR,CAAC;CAED,MAAM,UAAU,IAAI,QAAQ;CAK5B,IAAI,UAAU,SACZ,IAAI,UAAU;EACL;EACP,MAAM;CACR;CAIF,OAAO,IAAI,QAAQ;AACrB;;;;;;;;;;;;;;;;;;;;;;;;;;AA2BA,SAAgB,wBACd,KACA,UACA,8BAAwD,CAAC,GACzD,UAAkC,CAAC,GACnC;CACA,QAAM,gBAAgB;EACpB,IACE,CAAC,IAAI,WACL,QAAQ,YACR,OAAO,yBAAyB,YAEhC;EAGF,MAAM,WAAW,IAAI,sBAAsB,CAAC,WAAW;GACrD,SAAS,KAAK;EAChB,GAAG,2BAA2B;EAE9B,SAAS,QAAQ,IAAI,OAAO;EAE5B,aAAa;GACX,SAAS,WAAW;EACtB;CACF,GAAG;EAAC;EAAU;EAA6B,QAAQ;EAAU;CAAG,CAAC;AACnE;;;;;;;;;;;;;;AAeA,SAAgB,gBAAmB,KAA6B;CAC9D,MAAM,WAAW,QAAM,OAAU,IAAI;CACrC,QAAM,oBAAoB,WAAW,SAAS,SAAU,CAAC,CAAC;CAC1D,OAAO;AACT"} | ||
| {"version":3,"file":"utils.js","names":[],"sources":["../../src/utils.ts"],"sourcesContent":["'use client'\nimport * as React from 'react'\nimport { isServer } from '@tanstack/router-core/isServer'\n\n// Safe version of React.use() that will not cause compilation errors against\n// React 18 with Webpack, which statically analyzes imports and fails when it\n// sees React.use referenced (since 'use' is not exported from React 18).\n// This uses a dynamic string lookup to avoid the static analysis.\n// eslint-disable-next-line prefer-const -- Must be `let` to prevent bundler constant-folding\nlet REACT_USE = 'use'\n\n/**\n * React.use if available (React 19+), undefined otherwise.\n * Use dynamic lookup to avoid Webpack compilation errors with React 18.\n */\nexport const reactUse:\n | (<T>(usable: Promise<T> | React.Context<T>) => T)\n | undefined = (React as any)[REACT_USE]\n\nexport function useStableCallback<T extends (...args: Array<any>) => any>(\n fn: T,\n): T {\n const fnRef = React.useRef(fn)\n fnRef.current = fn\n\n const ref = React.useRef((...args: Array<any>) => fnRef.current(...args))\n return ref.current as T\n}\n\nexport const useLayoutEffect =\n (isServer ?? typeof window === 'undefined')\n ? React.useEffect\n : React.useLayoutEffect\n\n/**\n * Taken from https://www.developerway.com/posts/implementing-advanced-use-previous-hook#part3\n */\nexport function usePrevious<T>(value: T): T | null {\n // initialise the ref with previous and current values\n const ref = React.useRef<{ value: T; prev: T | null }>({\n value: value,\n prev: null,\n })\n\n const current = ref.current.value\n\n // if the value passed into hook doesn't match what we store as \"current\"\n // move the \"current\" to the \"previous\"\n // and store the passed value as \"current\"\n if (value !== current) {\n ref.current = {\n value: value,\n prev: current,\n }\n }\n\n // return the previous value only\n return ref.current.prev\n}\n\n/**\n * React hook to wrap `IntersectionObserver`.\n *\n * This hook will create an `IntersectionObserver` and observe the ref passed to it.\n *\n * When the intersection changes, the callback will be called with the `IntersectionObserverEntry`.\n *\n * @param ref - The ref to observe\n * @param intersectionObserverOptions - The options to pass to the IntersectionObserver\n * @param options - The options to pass to the hook\n * @param callback - The callback to call when the intersection changes\n * @returns The IntersectionObserver instance\n * @example\n * ```tsx\n * const MyComponent = () => {\n * const ref = React.useRef<HTMLDivElement>(null)\n * useIntersectionObserver(\n * ref,\n * (entry) => { doSomething(entry) },\n * { rootMargin: '10px' },\n * { disabled: false }\n * )\n * return <div ref={ref} />\n * ```\n */\nexport function useIntersectionObserver<T extends Element>(\n ref: React.RefObject<T | null>,\n callback: (entry: IntersectionObserverEntry | undefined) => void,\n intersectionObserverOptions: IntersectionObserverInit = {},\n options: { disabled?: boolean } = {},\n) {\n React.useEffect(() => {\n if (\n !ref.current ||\n options.disabled ||\n typeof IntersectionObserver !== 'function'\n ) {\n return\n }\n\n const observer = new IntersectionObserver(([entry]) => {\n callback(entry)\n }, intersectionObserverOptions)\n\n observer.observe(ref.current)\n\n return () => {\n observer.disconnect()\n }\n }, [callback, intersectionObserverOptions, options.disabled, ref])\n}\n\n/**\n * React hook to take a `React.ForwardedRef` and returns a `ref` that can be used on a DOM element.\n *\n * @param ref - The forwarded ref\n * @returns The inner ref returned by `useRef`\n * @example\n * ```tsx\n * const MyComponent = React.forwardRef((props, ref) => {\n * const innerRef = useForwardedRef(ref)\n * return <div ref={innerRef} />\n * })\n * ```\n */\nexport function useForwardedRef<T>(ref?: React.ForwardedRef<T>) {\n const innerRef = React.useRef<T>(null)\n React.useImperativeHandle(ref, () => innerRef.current!, [])\n return innerRef\n}\n"],"mappings":";;;;;;;AAeA,IAAa,WAEI,QAAc;AAY/B,IAAa,kBACV,YAAY,OAAO,WAAW,cAC3B,QAAM,YACN,QAAM;;;;;;;;;;;;;;;;;;;;;;;;;;AAqDZ,SAAgB,wBACd,KACA,UACA,8BAAwD,CAAC,GACzD,UAAkC,CAAC,GACnC;CACA,QAAM,gBAAgB;EACpB,IACE,CAAC,IAAI,WACL,QAAQ,YACR,OAAO,yBAAyB,YAEhC;EAGF,MAAM,WAAW,IAAI,sBAAsB,CAAC,WAAW;GACrD,SAAS,KAAK;EAChB,GAAG,2BAA2B;EAE9B,SAAS,QAAQ,IAAI,OAAO;EAE5B,aAAa;GACX,SAAS,WAAW;EACtB;CACF,GAAG;EAAC;EAAU;EAA6B,QAAQ;EAAU;CAAG,CAAC;AACnE;;;;;;;;;;;;;;AAeA,SAAgB,gBAAmB,KAA6B;CAC9D,MAAM,WAAW,QAAM,OAAU,IAAI;CACrC,QAAM,oBAAoB,WAAW,SAAS,SAAU,CAAC,CAAC;CAC1D,OAAO;AACT"} |
+5
-4
| { | ||
| "name": "@tanstack/react-router", | ||
| "version": "1.170.18", | ||
| "version": "1.170.19-pre.0", | ||
| "description": "Modern and scalable routing for React applications", | ||
@@ -81,3 +81,3 @@ "author": "Tanner Linsley", | ||
| "@tanstack/history": "1.162.0", | ||
| "@tanstack/router-core": "1.171.15" | ||
| "@tanstack/router-core": "1.171.16-pre.0" | ||
| }, | ||
@@ -87,2 +87,3 @@ "devDependencies": { | ||
| "@testing-library/react": "^16.2.0", | ||
| "@tanstack/react-query": "^5.99.0", | ||
| "@types/node": ">=20", | ||
@@ -104,3 +105,2 @@ "@vitejs/plugin-react": "^4.3.4", | ||
| "test:types": "pnpm run \"/^test:types:ts[0-9]{2}$/\"", | ||
| "test:types:ts55": "node ../../node_modules/typescript55/lib/tsc.js -p tsconfig.legacy.json", | ||
| "test:types:ts56": "node ../../node_modules/typescript56/lib/tsc.js -p tsconfig.legacy.json", | ||
@@ -110,3 +110,4 @@ "test:types:ts57": "node ../../node_modules/typescript57/lib/tsc.js -p tsconfig.legacy.json", | ||
| "test:types:ts59": "node ../../node_modules/typescript59/lib/tsc.js -p tsconfig.legacy.json", | ||
| "test:types:ts60": "tsc -p tsconfig.legacy.json", | ||
| "test:types:ts60": "tsc6 -p tsconfig.legacy.json", | ||
| "test:types:ts70": "tsc -p tsconfig.legacy.json", | ||
| "test:unit": "vitest", | ||
@@ -113,0 +114,0 @@ "test:unit:dev": "pnpm run test:unit --watch --hideSkippedTests", |
+17
-37
@@ -8,3 +8,3 @@ 'use client' | ||
| export function CatchBoundary(props: { | ||
| getResetKey: () => number | string | ||
| getResetKey: () => unknown | ||
| children: React.ReactNode | ||
@@ -14,35 +14,16 @@ errorComponent?: ErrorRouteComponent | ||
| }) { | ||
| const errorComponent = props.errorComponent ?? ErrorComponent | ||
| return ( | ||
| <CatchBoundaryImpl | ||
| getResetKey={props.getResetKey} | ||
| onCatch={props.onCatch} | ||
| children={({ error, reset }) => { | ||
| if (error) { | ||
| return React.createElement(errorComponent, { | ||
| error, | ||
| reset, | ||
| }) | ||
| } | ||
| return props.children | ||
| }} | ||
| /> | ||
| ) | ||
| return <CatchBoundaryImpl {...props} /> | ||
| } | ||
| class CatchBoundaryImpl extends React.Component<{ | ||
| getResetKey: () => number | string | ||
| children: (props: { | ||
| error: Error | null | ||
| reset: () => void | ||
| }) => React.ReactNode | ||
| getResetKey: () => unknown | ||
| children: React.ReactNode | ||
| errorComponent?: ErrorRouteComponent | ||
| onCatch?: (error: Error, errorInfo: ErrorInfo) => void | ||
| }> { | ||
| state = { error: null } as { error: Error | null; resetKey?: string | number } | ||
| state = { error: null } as { error: Error | null; resetKey?: unknown } | ||
| static getDerivedStateFromProps( | ||
| props: { getResetKey: () => string | number }, | ||
| state: { resetKey?: string | number; error: Error | null }, | ||
| props: { getResetKey: () => unknown }, | ||
| state: { resetKey?: unknown; error: Error | null }, | ||
| ) { | ||
@@ -60,17 +41,16 @@ const resetKey = props.getResetKey() | ||
| } | ||
| reset() { | ||
| reset = () => { | ||
| this.setState({ error: null }) | ||
| } | ||
| componentDidCatch(error: Error, errorInfo: ErrorInfo) { | ||
| if (this.props.onCatch) { | ||
| this.props.onCatch(error, errorInfo) | ||
| } | ||
| this.props.onCatch?.(error, errorInfo) | ||
| } | ||
| render() { | ||
| return this.props.children({ | ||
| error: this.state.error, | ||
| reset: () => { | ||
| this.reset() | ||
| }, | ||
| }) | ||
| const error = this.state.error | ||
| return error | ||
| ? React.createElement(this.props.errorComponent ?? ErrorComponent, { | ||
| error, | ||
| reset: this.reset, | ||
| }) | ||
| : this.props.children | ||
| } | ||
@@ -77,0 +57,0 @@ } |
@@ -34,7 +34,3 @@ 'use client' | ||
| export function ClientOnly({ children, fallback = null }: ClientOnlyProps) { | ||
| return useHydrated() ? ( | ||
| <React.Fragment>{children}</React.Fragment> | ||
| ) : ( | ||
| <React.Fragment>{fallback}</React.Fragment> | ||
| ) | ||
| return <React.Fragment>{useHydrated() ? children : fallback}</React.Fragment> | ||
| } | ||
@@ -41,0 +37,0 @@ |
+8
-221
| import * as React from 'react' | ||
| import { useStore } from '@tanstack/react-store' | ||
| import { | ||
| _getAssetMatches, | ||
| appendUniqueUserTags, | ||
@@ -25,2 +26,3 @@ deepEqual, | ||
| ): Array<RouterManagedTag> { | ||
| matches = _getAssetMatches(matches) | ||
| const routeMeta = matches | ||
@@ -191,3 +193,3 @@ .map((match) => match.meta) | ||
| /** | ||
| * Build the list of head/link/meta/script tags to render for active matches. | ||
| * Build the head/link/meta/script tags from the renderable presented prefix. | ||
| * Used internally by `HeadContent`. | ||
@@ -209,224 +211,9 @@ */ | ||
| // eslint-disable-next-line react-hooks/rules-of-hooks -- condition is static | ||
| const routeMeta = useStore( | ||
| router.stores.matches, | ||
| (matches) => { | ||
| return matches | ||
| .map((match) => match.meta) | ||
| .filter((meta) => meta !== undefined) | ||
| }, | ||
| deepEqual, | ||
| const selectTags = React.useCallback( | ||
| (matches: Array<AnyRouteMatch>) => | ||
| buildTagsFromMatches(router, nonce, matches, assetCrossOrigin), | ||
| [assetCrossOrigin, nonce, router], | ||
| ) | ||
| // eslint-disable-next-line react-hooks/rules-of-hooks -- condition is static | ||
| const meta: Array<RouterManagedTag> = React.useMemo(() => { | ||
| const resultMeta: Array<RouterManagedTag> = [] | ||
| const metaByAttribute: Record<string, true> = {} | ||
| let title: RouterManagedTag | undefined | ||
| for (let i = routeMeta.length - 1; i >= 0; i--) { | ||
| const metas = routeMeta[i]! | ||
| for (let j = metas.length - 1; j >= 0; j--) { | ||
| const m = metas[j] | ||
| if (!m) continue | ||
| if (m.title) { | ||
| if (!title) { | ||
| title = { | ||
| tag: 'title', | ||
| children: m.title, | ||
| } | ||
| } | ||
| } else if ('script:ld+json' in m) { | ||
| // Handle JSON-LD structured data | ||
| // Content is HTML-escaped to prevent XSS when injected via dangerouslySetInnerHTML | ||
| try { | ||
| const json = JSON.stringify(m['script:ld+json']) | ||
| resultMeta.push({ | ||
| tag: 'script', | ||
| attrs: { | ||
| type: 'application/ld+json', | ||
| }, | ||
| children: escapeHtml(json), | ||
| }) | ||
| } catch { | ||
| // Skip invalid JSON-LD objects | ||
| } | ||
| } else { | ||
| const attribute = m.name ?? m.property | ||
| if (attribute) { | ||
| if (metaByAttribute[attribute]) { | ||
| continue | ||
| } else { | ||
| metaByAttribute[attribute] = true | ||
| } | ||
| } | ||
| resultMeta.push({ | ||
| tag: 'meta', | ||
| attrs: { | ||
| ...m, | ||
| nonce, | ||
| }, | ||
| }) | ||
| } | ||
| } | ||
| } | ||
| if (title) { | ||
| resultMeta.push(title) | ||
| } | ||
| if (nonce) { | ||
| resultMeta.push({ | ||
| tag: 'meta', | ||
| attrs: { | ||
| property: 'csp-nonce', | ||
| content: nonce, | ||
| }, | ||
| }) | ||
| } | ||
| resultMeta.reverse() | ||
| return resultMeta | ||
| }, [routeMeta, nonce]) | ||
| // eslint-disable-next-line react-hooks/rules-of-hooks -- condition is static | ||
| const links = useStore( | ||
| router.stores.matches, | ||
| (matches) => { | ||
| const constructed = matches | ||
| .flatMap((match) => match.links ?? []) | ||
| .filter((link) => link !== undefined) | ||
| .map((link) => ({ | ||
| tag: 'link', | ||
| attrs: { | ||
| ...link, | ||
| nonce, | ||
| }, | ||
| })) satisfies Array<RouterManagedTag> | ||
| return constructed | ||
| }, | ||
| deepEqual, | ||
| ) | ||
| // eslint-disable-next-line react-hooks/rules-of-hooks -- condition is static | ||
| const manifestCssTags = useStore( | ||
| router.stores.matches, | ||
| (matches) => { | ||
| const manifest = router.ssr?.manifest | ||
| const tags: Array<RouterManagedTag> = [] | ||
| if (!manifest) { | ||
| return tags | ||
| } | ||
| matches.forEach((match) => { | ||
| manifest.routes[match.routeId]?.css?.forEach((link) => { | ||
| const resolvedLink = resolveManifestCssLink(link) | ||
| tags.push({ | ||
| tag: 'link', | ||
| attrs: { | ||
| rel: 'stylesheet', | ||
| ...resolvedLink, | ||
| crossOrigin: | ||
| getAssetCrossOrigin(assetCrossOrigin, 'stylesheet') ?? | ||
| resolvedLink.crossOrigin, | ||
| suppressHydrationWarning: true, | ||
| nonce, | ||
| }, | ||
| }) | ||
| }) | ||
| }) | ||
| if (manifest.inlineStyle) { | ||
| tags.push({ | ||
| tag: 'style', | ||
| attrs: { | ||
| ...manifest.inlineStyle.attrs, | ||
| nonce, | ||
| }, | ||
| children: manifest.inlineStyle.children, | ||
| inlineCss: true, | ||
| }) | ||
| } | ||
| return tags | ||
| }, | ||
| deepEqual, | ||
| ) | ||
| // eslint-disable-next-line react-hooks/rules-of-hooks -- condition is static | ||
| const preloadLinks = useStore( | ||
| router.stores.matches, | ||
| (matches) => { | ||
| const preloadLinks: Array<RouterManagedTag> = [] | ||
| const manifest = router.ssr?.manifest | ||
| if (!manifest) { | ||
| return preloadLinks | ||
| } | ||
| matches.forEach((match) => { | ||
| manifest.routes[match.routeId]?.preloads?.forEach((preload) => { | ||
| preloadLinks.push({ | ||
| tag: 'link', | ||
| attrs: { | ||
| ...getScriptPreloadAttrs(manifest, preload, assetCrossOrigin), | ||
| nonce, | ||
| }, | ||
| }) | ||
| }) | ||
| }) | ||
| return preloadLinks | ||
| }, | ||
| deepEqual, | ||
| ) | ||
| // eslint-disable-next-line react-hooks/rules-of-hooks -- condition is static | ||
| const styles = useStore( | ||
| router.stores.matches, | ||
| (matches) => { | ||
| return matches | ||
| .flatMap((match) => match.styles ?? []) | ||
| .filter((style) => style !== undefined) | ||
| .map(({ children, ...attrs }) => ({ | ||
| tag: 'style', | ||
| attrs: { | ||
| ...attrs, | ||
| nonce, | ||
| }, | ||
| children: children as string | undefined, | ||
| })) satisfies Array<RouterManagedTag> | ||
| }, | ||
| deepEqual, | ||
| ) | ||
| // eslint-disable-next-line react-hooks/rules-of-hooks -- condition is static | ||
| const headScripts: Array<RouterManagedTag> = useStore( | ||
| router.stores.matches, | ||
| (matches) => { | ||
| return matches | ||
| .flatMap((match) => match.headScripts ?? []) | ||
| .filter((script) => script !== undefined) | ||
| .map(({ children, ...script }) => ({ | ||
| tag: 'script', | ||
| attrs: { | ||
| ...script, | ||
| nonce, | ||
| }, | ||
| children: children as string | undefined, | ||
| })) satisfies Array<RouterManagedTag> | ||
| }, | ||
| deepEqual, | ||
| ) | ||
| const tags: Array<RouterManagedTag> = [] | ||
| appendUniqueUserTags(tags, meta) | ||
| tags.push(...preloadLinks) | ||
| appendUniqueUserTags(tags, links) | ||
| tags.push(...manifestCssTags) | ||
| appendUniqueUserTags(tags, styles) | ||
| appendUniqueUserTags(tags, headScripts) | ||
| return tags | ||
| return useStore(router.stores.matches, selectTags, deepEqual) | ||
| } |
| import * as React from 'react' | ||
| import { isModuleNotFoundError } from '@tanstack/router-core' | ||
| import { isServer } from '@tanstack/router-core/isServer' | ||
| import { reactUse } from './utils' | ||
@@ -27,12 +28,16 @@ import type { AsyncRouteComponent } from './route' | ||
| let error: any | ||
| let reload: boolean | ||
| const load = () => { | ||
| if (!loadPromise) { | ||
| error = undefined | ||
| loadPromise = importer() | ||
| .then((res) => { | ||
| loadPromise = undefined | ||
| // Keep browser preload behavior unchanged; SSR can reuse the import. | ||
| if (!(isServer ?? typeof window === 'undefined')) { | ||
| loadPromise = undefined | ||
| } | ||
| comp = res[exportName ?? 'default'] | ||
| }) | ||
| .catch((err) => { | ||
| loadPromise = undefined | ||
| // We don't want an error thrown from preload in this case, because | ||
@@ -42,24 +47,2 @@ // there's nothing we want to do about module not found during preload. | ||
| error = err | ||
| // If the load fails due to module not found, it may mean a new version of | ||
| // the build was deployed and the user's browser is still using an old version. | ||
| // If this happens, the old version in the user's browser would have an outdated | ||
| // URL to the lazy module. | ||
| // In that case, we want to attempt one window refresh to get the latest. | ||
| if (isModuleNotFoundError(error)) { | ||
| if ( | ||
| error instanceof Error && | ||
| typeof window !== 'undefined' && | ||
| typeof sessionStorage !== 'undefined' | ||
| ) { | ||
| // Again, we want to reload one time on module not found error and not enter | ||
| // a reload loop if there is some other issue besides an old deploy. | ||
| // That's why we store our reload attempt in sessionStorage. | ||
| // Use error.message as key because it contains the module path that failed. | ||
| const storageKey = `tanstack_router_reload:${error.message}` | ||
| if (!sessionStorage.getItem(storageKey)) { | ||
| sessionStorage.setItem(storageKey, '1') | ||
| reload = true | ||
| } | ||
| } | ||
| } | ||
| }) | ||
@@ -72,11 +55,19 @@ } | ||
| const lazyComp = function Lazy(props: any) { | ||
| // Now that we're out of preload and into actual render path, | ||
| if (reload) { | ||
| // If it was a module loading error, | ||
| // throw eternal suspense while we wait for window to reload | ||
| window.location.reload() | ||
| throw new Promise(() => {}) | ||
| } | ||
| if (error) { | ||
| // Otherwise, just throw the error | ||
| // A missing module can mean that a newer deployment replaced the URL. | ||
| // Reload only for the error that is still current at render time, so a | ||
| // successful retry cannot leave a stale reload request armed. | ||
| if ( | ||
| isModuleNotFoundError(error) && | ||
| !(isServer ?? typeof window === 'undefined') && | ||
| typeof sessionStorage !== 'undefined' | ||
| ) { | ||
| const storageKey = `tanstack_router_reload:${error.message}` | ||
| if (!sessionStorage.getItem(storageKey)) { | ||
| sessionStorage.setItem(storageKey, '1') | ||
| window.location.reload() | ||
| // Suspend forever while the document reloads. | ||
| throw new Promise(() => {}) | ||
| } | ||
| } | ||
| throw error | ||
@@ -83,0 +74,0 @@ } |
+78
-407
@@ -5,10 +5,3 @@ 'use client' | ||
| import { useStore } from '@tanstack/react-store' | ||
| import { | ||
| createControlledPromise, | ||
| getLocationChangeInfo, | ||
| invariant, | ||
| isNotFound, | ||
| isRedirect, | ||
| rootRouteId, | ||
| } from '@tanstack/router-core' | ||
| import { isNotFound, rootRouteId } from '@tanstack/router-core' | ||
| import { isServer } from '@tanstack/router-core/isServer' | ||
@@ -23,18 +16,22 @@ import { CatchBoundary, ErrorComponent } from './CatchBoundary' | ||
| import { ClientOnly } from './ClientOnly' | ||
| import { useLayoutEffect } from './utils' | ||
| import type { | ||
| AnyRoute, | ||
| AnyRouteMatch, | ||
| ParsedLocation, | ||
| RootRouteOptions, | ||
| } from '@tanstack/router-core' | ||
| export function renderPending( | ||
| router: ReturnType<typeof useRouter>, | ||
| route?: AnyRoute, | ||
| ) { | ||
| const PendingComponent = | ||
| route?.options.pendingComponent ?? router.options.defaultPendingComponent | ||
| return PendingComponent ? <PendingComponent /> : null | ||
| } | ||
| type OutletMatchSelection = [ | ||
| routeId: string | undefined, | ||
| parentGlobalNotFound: boolean, | ||
| parentNotFoundError: unknown, | ||
| ] | ||
| const matchViewFieldsEqual = (a: AnyRouteMatch, b: AnyRouteMatch) => | ||
| a.routeId === b.routeId && a._displayPending === b._displayPending | ||
| const outletMatchSelectionEqual = ( | ||
@@ -46,5 +43,5 @@ a: OutletMatchSelection, | ||
| export const Match = React.memo(function MatchImpl({ | ||
| matchId, | ||
| routeId, | ||
| }: { | ||
| matchId: string | ||
| routeId: string | ||
| }) { | ||
@@ -54,99 +51,23 @@ const router = useRouter() | ||
| if (isServer ?? router.isServer) { | ||
| const match = router.stores.matchStores.get(matchId)?.get() | ||
| if (!match) { | ||
| if (process.env.NODE_ENV !== 'production') { | ||
| throw new Error( | ||
| `Invariant failed: Could not find match for matchId "${matchId}". Please file an issue!`, | ||
| ) | ||
| } | ||
| invariant() | ||
| } | ||
| const routeId = match.routeId as string | ||
| const parentRouteId = (router.routesById[routeId] as AnyRoute).parentRoute | ||
| ?.id | ||
| return ( | ||
| <MatchView | ||
| router={router} | ||
| matchId={matchId} | ||
| resetKey={router.stores.loadedAt.get()} | ||
| matchState={{ | ||
| routeId, | ||
| ssr: match.ssr, | ||
| _displayPending: match._displayPending, | ||
| parentRouteId, | ||
| }} | ||
| /> | ||
| ) | ||
| const match = router.stores.byRoute.get(routeId)!.get()! | ||
| return <MatchView router={router} match={match} /> | ||
| } | ||
| // Subscribe directly to the match store from the pool. | ||
| // The matchId prop is stable for this component's lifetime (set by Outlet), | ||
| // and reconcileMatchPool reuses stores for the same matchId. | ||
| const matchStore = router.stores.matchStores.get(matchId) | ||
| if (!matchStore) { | ||
| if (process.env.NODE_ENV !== 'production') { | ||
| throw new Error( | ||
| `Invariant failed: Could not find match for matchId "${matchId}". Please file an issue!`, | ||
| ) | ||
| } | ||
| invariant() | ||
| } | ||
| const matchStore = router.stores.getMatchStore(routeId) | ||
| // eslint-disable-next-line react-hooks/rules-of-hooks | ||
| const resetKey = useStore(router.stores.loadedAt, (loadedAt) => loadedAt) | ||
| // eslint-disable-next-line react-hooks/rules-of-hooks | ||
| const match = useStore(matchStore, (value) => value, matchViewFieldsEqual) | ||
| // eslint-disable-next-line react-hooks/rules-of-hooks | ||
| const matchState = React.useMemo(() => { | ||
| const routeId = match.routeId as string | ||
| const parentRouteId = (router.routesById[routeId] as AnyRoute).parentRoute | ||
| ?.id | ||
| return { | ||
| routeId, | ||
| ssr: match.ssr, | ||
| _displayPending: match._displayPending, | ||
| parentRouteId: parentRouteId as string | undefined, | ||
| } satisfies MatchViewState | ||
| }, [match._displayPending, match.routeId, match.ssr, router.routesById]) | ||
| return ( | ||
| <MatchView | ||
| router={router} | ||
| matchId={matchId} | ||
| resetKey={resetKey} | ||
| matchState={matchState} | ||
| /> | ||
| ) | ||
| const match = useStore(matchStore, (value) => value) | ||
| return <MatchView router={router} match={match!} /> | ||
| }) | ||
| type MatchViewState = { | ||
| routeId: string | ||
| ssr: boolean | 'data-only' | undefined | ||
| _displayPending: boolean | undefined | ||
| parentRouteId: string | undefined | ||
| } | ||
| function MatchView({ | ||
| router, | ||
| matchId, | ||
| resetKey, | ||
| matchState, | ||
| match, | ||
| }: { | ||
| router: ReturnType<typeof useRouter> | ||
| matchId: string | ||
| resetKey: number | ||
| matchState: MatchViewState | ||
| match: AnyRouteMatch | ||
| }) { | ||
| const route: AnyRoute = router.routesById[matchState.routeId] | ||
| const route: AnyRoute = router.routesById[match.routeId] | ||
| const PendingComponent = | ||
| route.options.pendingComponent ?? router.options.defaultPendingComponent | ||
| const pendingElement = renderPending(router, route) | ||
| const pendingElement = PendingComponent ? <PendingComponent /> : null | ||
| const routeErrorComponent = | ||
@@ -158,3 +79,3 @@ route.options.errorComponent ?? router.options.defaultErrorComponent | ||
| const routeNotFoundComponent = route.isRoot | ||
| ? // If it's the root route, use the globalNotFound option, with fallback to the notFoundRoute's component | ||
| ? // If it's the root route, use the _notFound option, with fallback to the notFoundRoute's component | ||
| (route.options.notFoundComponent ?? | ||
@@ -164,10 +85,7 @@ router.options.notFoundRoute?.options.component) | ||
| const resolvedNoSsr = | ||
| matchState.ssr === false || matchState.ssr === 'data-only' | ||
| const resolvedNoSsr = match.ssr === false || match.ssr === 'data-only' | ||
| const ResolvedSuspenseBoundary = | ||
| // If we're on the root route, allow forcefully wrapping in suspense | ||
| (!route.isRoot || route.options.wrapInSuspense || resolvedNoSsr) && | ||
| (route.options.wrapInSuspense ?? | ||
| PendingComponent ?? | ||
| ((route.options.errorComponent as any)?.preload || resolvedNoSsr)) | ||
| pendingElement ?? | ||
| ((route.options.errorComponent as any)?.preload || resolvedNoSsr)) | ||
| ? React.Suspense | ||
@@ -189,15 +107,15 @@ : SafeFragment | ||
| <ShellComponent> | ||
| <matchContext.Provider value={matchId}> | ||
| <matchContext.Provider value={match.routeId}> | ||
| <ResolvedSuspenseBoundary fallback={pendingElement}> | ||
| <ResolvedCatchBoundary | ||
| getResetKey={() => resetKey} | ||
| errorComponent={routeErrorComponent || ErrorComponent} | ||
| getResetKey={() => match} | ||
| errorComponent={routeErrorComponent as any} | ||
| onCatch={(error, errorInfo) => { | ||
| // Forward not found errors (we don't want to show the error component for these) | ||
| if (isNotFound(error)) { | ||
| error.routeId ??= matchState.routeId as any | ||
| error.routeId ??= match.routeId | ||
| throw error | ||
| } | ||
| if (process.env.NODE_ENV !== 'production') { | ||
| console.warn(`Warning: Error in route match: ${matchId}`) | ||
| console.warn(`Warning: Error in route match: ${match.id}`) | ||
| } | ||
@@ -209,22 +127,20 @@ routeOnCatch?.(error, errorInfo) | ||
| fallback={(error) => { | ||
| error.routeId ??= matchState.routeId as any | ||
| error.routeId ??= match.routeId | ||
| // If the current not found handler doesn't exist or it has a | ||
| // route ID which doesn't match the current route, rethrow the error | ||
| if ( | ||
| !routeNotFoundComponent || | ||
| (error.routeId && error.routeId !== matchState.routeId) || | ||
| (!error.routeId && !route.isRoot) | ||
| ) | ||
| if (error.routeId !== match.routeId) { | ||
| throw error | ||
| } | ||
| return React.createElement(routeNotFoundComponent, error as any) | ||
| return React.createElement( | ||
| routeNotFoundComponent!, | ||
| error as any, | ||
| ) | ||
| }} | ||
| > | ||
| {resolvedNoSsr || matchState._displayPending ? ( | ||
| {resolvedNoSsr ? ( | ||
| <ClientOnly fallback={pendingElement}> | ||
| <MatchInner matchId={matchId} /> | ||
| <MatchInner match={match} /> | ||
| </ClientOnly> | ||
| ) : ( | ||
| <MatchInner matchId={matchId} /> | ||
| <MatchInner match={match} /> | ||
| )} | ||
@@ -235,9 +151,6 @@ </ResolvedNotFoundBoundary> | ||
| </matchContext.Provider> | ||
| {matchState.parentRouteId === rootRouteId ? ( | ||
| <> | ||
| <OnRendered /> | ||
| {router.options.scrollRestoration && (isServer ?? router.isServer) ? ( | ||
| <ScrollRestoration /> | ||
| ) : null} | ||
| </> | ||
| {(isServer ?? router.isServer) && | ||
| route.parentRoute?.id === rootRouteId && | ||
| router.options.scrollRestoration ? ( | ||
| <ScrollRestoration /> | ||
| ) : null} | ||
@@ -248,175 +161,13 @@ </ShellComponent> | ||
| // On Rendered can't happen above the root layout because it needs to run after | ||
| // the route subtree has committed below the root layout. Keeping it here lets | ||
| // us fire onRendered even after a hydration mismatch above the root layout | ||
| // (like bad head/link tags, which is common). | ||
| function OnRendered() { | ||
| const router = useRouter() | ||
| if (isServer ?? router.isServer) { | ||
| return null | ||
| } | ||
| // 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 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 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 | ||
| }, [renderedLocationKey, router]) | ||
| return null | ||
| } | ||
| export const MatchInner = React.memo(function MatchInnerImpl({ | ||
| matchId, | ||
| match, | ||
| }: { | ||
| matchId: string | ||
| match: AnyRouteMatch | ||
| }): any { | ||
| const router = useRouter() | ||
| const getMatchPromise = ( | ||
| match: { | ||
| id: string | ||
| _nonReactive: { | ||
| displayPendingPromise?: Promise<void> | ||
| minPendingPromise?: Promise<void> | ||
| loadPromise?: Promise<void> | ||
| } | ||
| }, | ||
| key: 'displayPendingPromise' | 'minPendingPromise' | 'loadPromise', | ||
| ) => { | ||
| return ( | ||
| router.getMatch(match.id)?._nonReactive[key] ?? match._nonReactive[key] | ||
| ) | ||
| } | ||
| if (isServer ?? router.isServer) { | ||
| const match = router.stores.matchStores.get(matchId)?.get() | ||
| if (!match) { | ||
| if (process.env.NODE_ENV !== 'production') { | ||
| throw new Error( | ||
| `Invariant failed: Could not find match for matchId "${matchId}". Please file an issue!`, | ||
| ) | ||
| } | ||
| invariant() | ||
| } | ||
| const routeId = match.routeId as string | ||
| const route = router.routesById[routeId] as AnyRoute | ||
| const remountFn = | ||
| (router.routesById[routeId] as AnyRoute).options.remountDeps ?? | ||
| router.options.defaultRemountDeps | ||
| const remountDeps = remountFn?.({ | ||
| routeId, | ||
| loaderDeps: match.loaderDeps, | ||
| params: match._strictParams, | ||
| search: match._strictSearch, | ||
| }) | ||
| const key = remountDeps ? JSON.stringify(remountDeps) : undefined | ||
| const Comp = route.options.component ?? router.options.defaultComponent | ||
| const out = Comp ? <Comp key={key} /> : <Outlet /> | ||
| if (match._displayPending) { | ||
| throw getMatchPromise(match, 'displayPendingPromise') | ||
| } | ||
| if (match._forcePending) { | ||
| throw getMatchPromise(match, 'minPendingPromise') | ||
| } | ||
| if (match.status === 'pending') { | ||
| throw getMatchPromise(match, 'loadPromise') | ||
| } | ||
| if (match.status === 'notFound') { | ||
| if (!isNotFound(match.error)) { | ||
| if (process.env.NODE_ENV !== 'production') { | ||
| throw new Error('Invariant failed: Expected a notFound error') | ||
| } | ||
| invariant() | ||
| } | ||
| return renderRouteNotFound(router, route, match.error) | ||
| } | ||
| if (match.status === 'redirected') { | ||
| if (!isRedirect(match.error)) { | ||
| if (process.env.NODE_ENV !== 'production') { | ||
| throw new Error('Invariant failed: Expected a redirect error') | ||
| } | ||
| invariant() | ||
| } | ||
| throw getMatchPromise(match, 'loadPromise') | ||
| } | ||
| if (match.status === 'error') { | ||
| const RouteErrorComponent = | ||
| (route.options.errorComponent ?? | ||
| router.options.defaultErrorComponent) || | ||
| ErrorComponent | ||
| return ( | ||
| <RouteErrorComponent | ||
| error={match.error as any} | ||
| reset={undefined as any} | ||
| info={{ | ||
| componentStack: '', | ||
| }} | ||
| /> | ||
| ) | ||
| } | ||
| return out | ||
| } | ||
| const matchStore = router.stores.matchStores.get(matchId) | ||
| if (!matchStore) { | ||
| if (process.env.NODE_ENV !== 'production') { | ||
| throw new Error( | ||
| `Invariant failed: Could not find match for matchId "${matchId}". Please file an issue!`, | ||
| ) | ||
| } | ||
| invariant() | ||
| } | ||
| // eslint-disable-next-line react-hooks/rules-of-hooks | ||
| const match = useStore(matchStore, (value) => value) | ||
| const routeId = match.routeId as string | ||
| const routeId = match.routeId | ||
| const route = router.routesById[routeId] as AnyRoute | ||
| // eslint-disable-next-line react-hooks/rules-of-hooks | ||
| const key = React.useMemo(() => { | ||
| const remountFn = | ||
| (router.routesById[routeId] as AnyRoute).options.remountDeps ?? | ||
| router.options.defaultRemountDeps | ||
| route.options.remountDeps ?? router.options.defaultRemountDeps | ||
| const remountDeps = remountFn?.({ | ||
@@ -434,81 +185,22 @@ routeId, | ||
| match._strictSearch, | ||
| route.options.remountDeps, | ||
| router.options.defaultRemountDeps, | ||
| router.routesById, | ||
| ]) | ||
| // eslint-disable-next-line react-hooks/rules-of-hooks | ||
| const out = React.useMemo(() => { | ||
| const Comp = route.options.component ?? router.options.defaultComponent | ||
| if (Comp) { | ||
| return <Comp key={key} /> | ||
| } | ||
| return <Outlet /> | ||
| return Comp ? <Comp key={key} /> : <Outlet /> | ||
| }, [key, route.options.component, router.options.defaultComponent]) | ||
| if (match._displayPending) { | ||
| throw getMatchPromise(match, 'displayPendingPromise') | ||
| } | ||
| if (match._forcePending) { | ||
| throw getMatchPromise(match, 'minPendingPromise') | ||
| } | ||
| // see also hydrate() in packages/router-core/src/ssr/ssr-client.ts | ||
| if (match.status === 'pending') { | ||
| // We're pending, and if we have a minPendingMs, we need to wait for it | ||
| const pendingMinMs = | ||
| route.options.pendingMinMs ?? router.options.defaultPendingMinMs | ||
| if (pendingMinMs) { | ||
| const routerMatch = router.getMatch(match.id) | ||
| if (routerMatch && !routerMatch._nonReactive.minPendingPromise) { | ||
| // Create a promise that will resolve after the minPendingMs | ||
| if (!(isServer ?? router.isServer)) { | ||
| const minPendingPromise = createControlledPromise<void>() | ||
| routerMatch._nonReactive.minPendingPromise = minPendingPromise | ||
| setTimeout(() => { | ||
| minPendingPromise.resolve() | ||
| // We've handled the minPendingPromise, so we can delete it | ||
| routerMatch._nonReactive.minPendingPromise = undefined | ||
| }, pendingMinMs) | ||
| } | ||
| } | ||
| if (router._tx) { | ||
| throw router._tx[5] | ||
| } | ||
| throw getMatchPromise(match, 'loadPromise') | ||
| return renderPending(router, route) | ||
| } | ||
| if (match.status === 'notFound') { | ||
| if (!isNotFound(match.error)) { | ||
| if (process.env.NODE_ENV !== 'production') { | ||
| throw new Error('Invariant failed: Expected a notFound error') | ||
| } | ||
| invariant() | ||
| } | ||
| return renderRouteNotFound(router, route, match.error) | ||
| } | ||
| if (match.status === 'redirected') { | ||
| // A match can be observed as redirected during an in-flight transition, | ||
| // especially when pending UI is already rendering. Suspend on the match's | ||
| // load promise so React can abandon this stale render and continue the | ||
| // redirect transition. | ||
| if (!isRedirect(match.error)) { | ||
| if (process.env.NODE_ENV !== 'production') { | ||
| throw new Error('Invariant failed: Expected a redirect error') | ||
| } | ||
| invariant() | ||
| } | ||
| throw getMatchPromise(match, 'loadPromise') | ||
| } | ||
| if (match.status === 'error') { | ||
| // If we're on the server, we need to use React's new and super | ||
| // wonky api for throwing errors from a server side render inside | ||
| // of a suspense boundary. This is the only way to get | ||
| // renderToPipeableStream to not hang indefinitely. | ||
| // We'll serialize the error and rethrow it on the client. | ||
| if (isServer ?? router.isServer) { | ||
@@ -529,3 +221,2 @@ const RouteErrorComponent = | ||
| } | ||
| throw match.error | ||
@@ -545,32 +236,22 @@ } | ||
| const router = useRouter() | ||
| const matchId = React.useContext(matchContext) | ||
| const routeId = React.useContext(matchContext)! | ||
| let routeId: string | undefined | ||
| let parentGlobalNotFound = false | ||
| let childMatchId: string | undefined | ||
| let parentGlobalNotFound: boolean | ||
| let parentNotFoundError: unknown | ||
| let childRouteId: string | undefined | ||
| if (isServer ?? router.isServer) { | ||
| const matches = router.stores.matches.get() | ||
| const parentIndex = matchId | ||
| ? matches.findIndex((match) => match.id === matchId) | ||
| : -1 | ||
| const parentMatch = parentIndex >= 0 ? matches[parentIndex] : undefined | ||
| routeId = parentMatch?.routeId as string | undefined | ||
| parentGlobalNotFound = parentMatch?.globalNotFound ?? false | ||
| childMatchId = | ||
| parentIndex >= 0 ? (matches[parentIndex + 1]?.id as string) : undefined | ||
| const parentIndex = matches.findIndex((match) => match.routeId === routeId) | ||
| const parentMatch = matches[parentIndex]! | ||
| parentGlobalNotFound = !!parentMatch._notFound | ||
| parentNotFoundError = parentMatch.error | ||
| childRouteId = matches[parentIndex + 1]?.routeId | ||
| } else { | ||
| // Subscribe directly to the match store from the pool instead of | ||
| // the two-level byId → matchStore pattern. | ||
| const parentMatchStore = matchId | ||
| ? router.stores.matchStores.get(matchId) | ||
| : undefined | ||
| const parentMatchStore = router.stores.getMatchStore(routeId) | ||
| // eslint-disable-next-line react-hooks/rules-of-hooks | ||
| ;[routeId, parentGlobalNotFound] = useStore( | ||
| ;[parentGlobalNotFound, parentNotFoundError] = useStore( | ||
| parentMatchStore, | ||
| (match): OutletMatchSelection => [ | ||
| match?.routeId as string | undefined, | ||
| match?.globalNotFound ?? false, | ||
| ], | ||
| (match): OutletMatchSelection => [!!match!._notFound, match!.error], | ||
| outletMatchSelectionEqual, | ||
@@ -580,36 +261,26 @@ ) | ||
| // eslint-disable-next-line react-hooks/rules-of-hooks | ||
| childMatchId = useStore(router.stores.matchesId, (ids) => { | ||
| const index = ids.findIndex((id) => id === matchId) | ||
| return ids[index + 1] | ||
| childRouteId = useStore(router.stores.ids, (ids) => { | ||
| return ids[ids.indexOf(routeId) + 1] | ||
| }) | ||
| } | ||
| const route = routeId ? router.routesById[routeId] : undefined | ||
| const pendingElement = router.options.defaultPendingComponent ? ( | ||
| <router.options.defaultPendingComponent /> | ||
| ) : null | ||
| if (parentGlobalNotFound) { | ||
| if (!route) { | ||
| if (process.env.NODE_ENV !== 'production') { | ||
| throw new Error( | ||
| 'Invariant failed: Could not resolve route for Outlet render', | ||
| ) | ||
| } | ||
| invariant() | ||
| } | ||
| return renderRouteNotFound(router, route, undefined) | ||
| return renderRouteNotFound( | ||
| router, | ||
| router.routesById[routeId], | ||
| parentNotFoundError, | ||
| ) | ||
| } | ||
| if (!childMatchId) { | ||
| if (!childRouteId) { | ||
| return null | ||
| } | ||
| const nextMatch = <Match matchId={childMatchId} /> | ||
| const nextMatch = <Match routeId={childRouteId} /> | ||
| if (routeId === rootRouteId) { | ||
| return ( | ||
| <React.Suspense fallback={pendingElement}>{nextMatch}</React.Suspense> | ||
| <React.Suspense fallback={renderPending(router)}> | ||
| {nextMatch} | ||
| </React.Suspense> | ||
| ) | ||
@@ -616,0 +287,0 @@ } |
+37
-47
@@ -7,8 +7,9 @@ 'use client' | ||
| import { isServer } from '@tanstack/router-core/isServer' | ||
| import { CatchBoundary, ErrorComponent } from './CatchBoundary' | ||
| import { CatchBoundary } from './CatchBoundary' | ||
| import { useRouter } from './useRouter' | ||
| import { useStructuralSharing } from './useMatch' | ||
| import { useLayoutEffect } from './utils' | ||
| import { Transitioner } from './Transitioner' | ||
| import { matchContext } from './matchContext' | ||
| import { Match } from './Match' | ||
| import { Match, renderPending } from './Match' | ||
| import { SafeFragment } from './SafeFragment' | ||
@@ -52,19 +53,15 @@ import type { | ||
| const PendingComponent = | ||
| rootRoute.options.pendingComponent ?? router.options.defaultPendingComponent | ||
| const pendingElement = renderPending(router, rootRoute) | ||
| const pendingElement = PendingComponent ? <PendingComponent /> : null | ||
| // Do not render a root Suspense during SSR or hydrating from SSR | ||
| const ResolvedSuspense = | ||
| (isServer ?? router.isServer) || | ||
| (typeof document !== 'undefined' && router.ssr) | ||
| ? SafeFragment | ||
| : React.Suspense | ||
| (isServer ?? router.isServer) || router.ssr ? SafeFragment : React.Suspense | ||
| const inner = ( | ||
| <ResolvedSuspense fallback={pendingElement}> | ||
| <> | ||
| {!(isServer ?? router.isServer) && <Transitioner />} | ||
| <MatchesInner /> | ||
| </ResolvedSuspense> | ||
| <ResolvedSuspense fallback={pendingElement}> | ||
| <MatchesInner /> | ||
| </ResolvedSuspense> | ||
| </> | ||
| ) | ||
@@ -81,16 +78,18 @@ | ||
| const router = useRouter() | ||
| const _isServer = isServer ?? router.isServer | ||
| const matchId = _isServer | ||
| ? router.stores.firstId.get() | ||
| : // eslint-disable-next-line react-hooks/rules-of-hooks | ||
| useStore(router.stores.firstId, (id) => id) | ||
| const resetKey = _isServer | ||
| ? router.stores.loadedAt.get() | ||
| : // eslint-disable-next-line react-hooks/rules-of-hooks | ||
| useStore(router.stores.loadedAt, (loadedAt) => loadedAt) | ||
| const matches = | ||
| (isServer ?? router.isServer) | ||
| ? router.stores.matches.get() | ||
| : // eslint-disable-next-line react-hooks/rules-of-hooks | ||
| useStore(router.stores.matches, (value) => value) | ||
| const match = matches[0] | ||
| const routeId = match?.routeId | ||
| const matchComponent = matchId ? <Match matchId={matchId} /> : null | ||
| useLayoutEffect(() => { | ||
| router._rendered!(matches) | ||
| }, [matches, router]) | ||
| const matchComponent = routeId ? <Match routeId={routeId} /> : null | ||
| return ( | ||
| <matchContext.Provider value={matchId}> | ||
| <matchContext.Provider value={routeId}> | ||
| {router.options.disableGlobalCatchBoundary ? ( | ||
@@ -100,4 +99,3 @@ matchComponent | ||
| <CatchBoundary | ||
| getResetKey={() => resetKey} | ||
| errorComponent={ErrorComponent} | ||
| getResetKey={() => match} | ||
| onCatch={ | ||
@@ -150,3 +148,7 @@ process.env.NODE_ENV !== 'production' | ||
| // eslint-disable-next-line react-hooks/rules-of-hooks | ||
| useStore(router.stores.matchRouteDeps, (d) => d) | ||
| useStore(router.stores.location, (location) => location.href) | ||
| // eslint-disable-next-line react-hooks/rules-of-hooks | ||
| useStore(router.stores.resolvedLocation, (location) => location?.href) | ||
| // eslint-disable-next-line react-hooks/rules-of-hooks | ||
| useStore(router.stores.status, (status) => status) | ||
| } | ||
@@ -263,17 +265,5 @@ | ||
| /** | ||
| * Read the full array of active route matches or select a derived subset. | ||
| * | ||
| * Useful for debugging, breadcrumbs, or aggregating metadata across matches. | ||
| * | ||
| * @returns The array of matches (or the selected value). | ||
| * @link https://tanstack.com/router/latest/docs/framework/react/api/router/useMatchesHook | ||
| * Read the presented route matches above the current match, or select a | ||
| * derived value from them. | ||
| */ | ||
| /** | ||
| * Read the full array of active route matches or select a derived subset. | ||
| * | ||
| * Useful for debugging, breadcrumbs, or aggregating metadata across matches. | ||
| * | ||
| * @link https://tanstack.com/router/latest/docs/framework/react/api/router/useMatchesHook | ||
| */ | ||
| export function useParentMatches< | ||
@@ -287,3 +277,3 @@ TRouter extends AnyRouter = RegisteredRouter, | ||
| ): UseMatchesResult<TRouter, TSelected> { | ||
| const contextMatchId = React.useContext(matchContext) | ||
| const contextRouteId = React.useContext(matchContext) | ||
@@ -294,3 +284,3 @@ return useMatches({ | ||
| 0, | ||
| matches.findIndex((d) => d.id === contextMatchId), | ||
| matches.findIndex((d) => d.routeId === contextRouteId), | ||
| ) | ||
@@ -304,4 +294,4 @@ return opts?.select ? opts.select(matches) : matches | ||
| /** | ||
| * Read the array of active route matches that are children of the current | ||
| * match (or selected parent) in the match tree. | ||
| * Read the presented route matches below the current match, or select a | ||
| * derived value from them. | ||
| */ | ||
@@ -316,3 +306,3 @@ export function useChildMatches< | ||
| ): UseMatchesResult<TRouter, TSelected> { | ||
| const contextMatchId = React.useContext(matchContext) | ||
| const contextRouteId = React.useContext(matchContext) | ||
@@ -322,3 +312,3 @@ return useMatches({ | ||
| matches = matches.slice( | ||
| matches.findIndex((d) => d.id === contextMatchId) + 1, | ||
| matches.findIndex((d) => d.routeId === contextRouteId) + 1, | ||
| ) | ||
@@ -325,0 +315,0 @@ return opts?.select ? opts.select(matches) : matches |
@@ -53,4 +53,4 @@ 'use client' | ||
| /** | ||
| * Top-level component that renders the active route matches and provides the | ||
| * router to the React tree via context. | ||
| * Renders the current match presentation and provides the router to the React | ||
| * tree via context. | ||
| * | ||
@@ -57,0 +57,0 @@ * Accepts the same options as `createRouter` via props to update the router |
+29
-43
| import { useStore } from '@tanstack/react-store' | ||
| import { deepEqual } from '@tanstack/router-core' | ||
| import { _getAssetMatches, deepEqual } from '@tanstack/router-core' | ||
| import { isServer } from '@tanstack/router-core/isServer' | ||
@@ -20,19 +20,34 @@ import { Asset } from './Asset' | ||
| const getAssetScripts = (matches: Array<any>) => { | ||
| const assetScripts: Array<ScriptRenderAsset> = [] | ||
| const getScripts = (matches: Array<any>) => { | ||
| matches = _getAssetMatches(matches) | ||
| const scripts = matches | ||
| .flatMap((match) => match.scripts ?? []) | ||
| .filter(Boolean) | ||
| .map( | ||
| ({ children, ...script }) => | ||
| ({ | ||
| tag: 'script', | ||
| attrs: { | ||
| ...script, | ||
| suppressHydrationWarning: true, | ||
| nonce, | ||
| }, | ||
| children, | ||
| }) satisfies RouterManagedTag, | ||
| ) as Array<ScriptRenderAsset> | ||
| const manifest = router.ssr?.manifest | ||
| if (!manifest) { | ||
| return [] | ||
| return scripts | ||
| } | ||
| for (const match of matches) { | ||
| const scripts = manifest.routes[match.routeId]?.scripts | ||
| const manifestScripts = manifest.routes[match.routeId]?.scripts | ||
| if (!scripts) { | ||
| if (!manifestScripts) { | ||
| continue | ||
| } | ||
| for (const asset of scripts) { | ||
| assetScripts.push({ | ||
| for (const asset of manifestScripts) { | ||
| scripts.push({ | ||
| tag: 'script', | ||
@@ -48,41 +63,15 @@ attrs: { ...asset.attrs, nonce }, | ||
| return assetScripts | ||
| return scripts | ||
| } | ||
| const getScripts = (matches: Array<any>): Array<RouterManagedTag> => | ||
| ( | ||
| matches | ||
| .map((match) => match.scripts!) | ||
| .flat(1) | ||
| .filter(Boolean) as Array<RouterManagedTag> | ||
| ).map( | ||
| ({ children, ...script }) => | ||
| ({ | ||
| tag: 'script', | ||
| attrs: { | ||
| ...script, | ||
| suppressHydrationWarning: true, | ||
| nonce, | ||
| }, | ||
| children, | ||
| }) satisfies RouterManagedTag, | ||
| ) | ||
| if (isServer ?? router.isServer) { | ||
| const activeMatches = router.stores.matches.get() | ||
| const assetScripts = getAssetScripts(activeMatches) | ||
| const scripts = getScripts(activeMatches) | ||
| return renderScripts(router, scripts, assetScripts) | ||
| return renderScripts(router, scripts) | ||
| } | ||
| // eslint-disable-next-line react-hooks/rules-of-hooks -- condition is static | ||
| const assetScripts = useStore( | ||
| router.stores.matches, | ||
| getAssetScripts, | ||
| deepEqual, | ||
| ) | ||
| // eslint-disable-next-line react-hooks/rules-of-hooks -- condition is static | ||
| const scripts = useStore(router.stores.matches, getScripts, deepEqual) | ||
| return renderScripts(router, scripts, assetScripts) | ||
| return renderScripts(router, scripts) | ||
| } | ||
@@ -92,11 +81,8 @@ | ||
| router: ReturnType<typeof useRouter>, | ||
| scripts: Array<RouterManagedTag>, | ||
| assetScripts: Array<ScriptRenderAsset>, | ||
| scripts: Array<ScriptRenderAsset>, | ||
| ) { | ||
| const allScripts = [...scripts, ...assetScripts] as Array<ScriptRenderAsset> | ||
| if ((isServer ?? router.isServer) && router.serverSsr) { | ||
| const serverBufferedScript = router.serverSsr.takeBufferedScripts() | ||
| if (serverBufferedScript) { | ||
| allScripts.unshift(serverBufferedScript) | ||
| scripts.unshift(serverBufferedScript) | ||
| } | ||
@@ -107,3 +93,3 @@ } | ||
| <> | ||
| {allScripts.map((asset, i) => ( | ||
| {scripts.map((asset, i) => ( | ||
| <Asset {...asset} key={`tsr-scripts-${asset.tag}-${i}`} /> | ||
@@ -110,0 +96,0 @@ ))} |
@@ -74,3 +74,6 @@ import { PassThrough } from 'node:stream' | ||
| stream as unknown as ReadableStream, | ||
| { onAbort: () => stream.cancel().catch(() => {}) }, | ||
| { | ||
| signal: request.signal, | ||
| onAbort: () => stream.cancel().catch(() => {}), | ||
| }, | ||
| ) | ||
@@ -80,3 +83,6 @@ return createSsrStreamResponse( | ||
| new Response(responseStream as any, { | ||
| status: router.stores.statusCode.get(), | ||
| status: | ||
| router._serverResult?.type === 'render' | ||
| ? router._serverResult.status | ||
| : 200, | ||
| headers: responseHeaders, | ||
@@ -182,3 +188,3 @@ }), | ||
| reactAppPassthrough, | ||
| { onAbort: abortPipeable }, | ||
| { signal: request.signal, onAbort: abortPipeable }, | ||
| ) | ||
@@ -205,3 +211,6 @@ responseAttached = true | ||
| new Response(responseStream as any, { | ||
| status: router.stores.statusCode.get(), | ||
| status: | ||
| router._serverResult?.type === 'render' | ||
| ? router._serverResult.status | ||
| : 200, | ||
| headers: responseHeaders, | ||
@@ -208,0 +217,0 @@ }), |
@@ -24,3 +24,6 @@ import ReactDOMServer from 'react-dom/server' | ||
| return new Response(`<!DOCTYPE html>${html}`, { | ||
| status: router.stores.statusCode.get(), | ||
| status: | ||
| router._serverResult?.type === 'render' | ||
| ? router._serverResult.status | ||
| : 200, | ||
| headers: responseHeaders, | ||
@@ -27,0 +30,0 @@ }) |
@@ -6,12 +6,7 @@ import { hydrate } from '@tanstack/router-core/ssr/client' | ||
| let hydrationPromise: Promise<void | Array<Array<void>>> | undefined | ||
| let hydrationPromise: Promise<void> | undefined | ||
| export function RouterClient(props: { router: AnyRouter }) { | ||
| if (!hydrationPromise) { | ||
| if (!props.router.stores.matchesId.get().length) { | ||
| hydrationPromise = hydrate(props.router) | ||
| } else { | ||
| hydrationPromise = Promise.resolve() | ||
| } | ||
| } | ||
| hydrationPromise ??= hydrate(props.router).finally(() => window.$_TSR!.h()) | ||
| return ( | ||
@@ -18,0 +13,0 @@ <Await |
+108
-97
| 'use client' | ||
| import * as React from 'react' | ||
| import { batch, useStore } from '@tanstack/react-store' | ||
| import { getLocationChangeInfo, trimPathRight } from '@tanstack/router-core' | ||
| import { useLayoutEffect, usePrevious } from './utils' | ||
| import { useLayoutEffect } from './utils' | ||
| import { useRouter } from './useRouter' | ||
| import type { AnyRouteMatch } from '@tanstack/router-core' | ||
| export function Transitioner() { | ||
| const router = useRouter() | ||
| const mountLoadForRouter = React.useRef({ router, mounted: false }) | ||
| const acknowledgement = React.useRef< | ||
| [Array<AnyRouteMatch>, (rendered: boolean) => void] | undefined | ||
| >(undefined) | ||
| const mounted = | ||
| process.env.NODE_ENV !== 'production' | ||
| ? // eslint-disable-next-line react-hooks/rules-of-hooks | ||
| React.useRef(false) | ||
| : undefined | ||
| const [isTransitioning, setIsTransitioning] = React.useState(false) | ||
| // Track pending state changes | ||
| const isLoading = useStore(router.stores.isLoading, (value) => value) | ||
| const hasPending = useStore(router.stores.hasPending, (value) => value) | ||
| const previousIsLoading = usePrevious(isLoading) | ||
| const isAnyPending = isLoading || isTransitioning || hasPending | ||
| const previousIsAnyPending = usePrevious(isAnyPending) | ||
| const isPagePending = isLoading || hasPending | ||
| const previousIsPagePending = usePrevious(isPagePending) | ||
| router.startTransition = (fn: () => void) => { | ||
| setIsTransitioning(true) | ||
| React.startTransition(() => { | ||
| fn() | ||
| setIsTransitioning(false) | ||
| }) | ||
| // `<Transitioner>` precedes `<MatchesInner>`, so install the render | ||
| // acknowledgement before the latter can publish a rendered lane. | ||
| router._rendered = (matches) => { | ||
| const current = acknowledgement.current | ||
| if ( | ||
| current?.[0].length === matches.length && | ||
| current[0].every( | ||
| (match, index) => | ||
| match.id === matches[index]!.id && | ||
| match.abortController === matches[index]!.abortController && | ||
| match.status === matches[index]!.status, | ||
| ) | ||
| ) { | ||
| acknowledgement.current = undefined | ||
| current[1](true) | ||
| } | ||
| } | ||
| if (process.env.NODE_ENV === 'production') { | ||
| router.startTransition = (fn, expected, urgent) => | ||
| new Promise((resolve) => { | ||
| acknowledgement.current?.[1](false) | ||
| acknowledgement.current = [expected, resolve] | ||
| if (urgent) { | ||
| fn() | ||
| } else { | ||
| React.startTransition(fn) | ||
| } | ||
| }) | ||
| } else { | ||
| router.startTransition = (fn, expected, urgent) => | ||
| new Promise((resolve, reject) => { | ||
| acknowledgement.current?.[1](false) | ||
| const next: NonNullable<typeof acknowledgement.current> = [ | ||
| expected, | ||
| resolve, | ||
| ] | ||
| acknowledgement.current = next | ||
| try { | ||
| if (urgent) { | ||
| fn() | ||
| } else { | ||
| React.startTransition(fn) | ||
| } | ||
| } catch (cause) { | ||
| if (acknowledgement.current === next) { | ||
| acknowledgement.current = undefined | ||
| } | ||
| reject(cause) | ||
| } | ||
| }) | ||
| ;( | ||
| router as typeof router & { _cancelTransition?: () => void } | ||
| )._cancelTransition = () => { | ||
| const current = acknowledgement.current | ||
| acknowledgement.current = undefined | ||
| current?.[1](false) | ||
| } | ||
| } | ||
| // Subscribe to location changes | ||
| // and try to load the new location | ||
| React.useEffect(() => { | ||
| // Subscribe before canonicalizing so the initial URL has exactly one load. | ||
| useLayoutEffect(() => { | ||
| const unsub = router.history.subscribe(router.load) | ||
| if (mounted?.current) { | ||
| return unsub | ||
| } | ||
| if (mounted) { | ||
| mounted.current = true | ||
| } | ||
| router.updateLatestLocation() | ||
| const location = router.latestLocation | ||
| const nextLocation = router.buildLocation({ | ||
| to: router.latestLocation.pathname, | ||
| to: location.pathname, | ||
| search: true, | ||
@@ -49,84 +102,42 @@ params: true, | ||
| // Check if the current URL matches the canonical form. | ||
| // Compare publicHref (browser-facing URL) for consistency with | ||
| // the server-side redirect check in router.beforeLoad. | ||
| // Compare publicHref (browser-facing URL) consistently with server | ||
| // canonicalization. | ||
| if ( | ||
| trimPathRight(router.latestLocation.publicHref) !== | ||
| trimPathRight(location.publicHref) !== | ||
| trimPathRight(nextLocation.publicHref) | ||
| ) { | ||
| router.commitLocation({ ...nextLocation, replace: true }) | ||
| router.commitLocation({ | ||
| ...nextLocation, | ||
| replace: true, | ||
| ignoreBlocker: true, | ||
| }) | ||
| return unsub | ||
| } | ||
| return () => { | ||
| unsub() | ||
| } | ||
| }, [router, router.history]) | ||
| // Try to load the initial location | ||
| useLayoutEffect(() => { | ||
| const resolvedLocation = router.stores.resolvedLocation.get() | ||
| if ( | ||
| // if we are hydrating from SSR, loading is triggered in ssr-client | ||
| (typeof window !== 'undefined' && router.ssr) || | ||
| (mountLoadForRouter.current.router === router && | ||
| mountLoadForRouter.current.mounted) | ||
| resolvedLocation?.href === location.href && | ||
| resolvedLocation.state.__TSR_key === location.state.__TSR_key | ||
| ) { | ||
| return | ||
| acknowledgement.current = [ | ||
| router.stores.matches.get(), | ||
| (rendered) => { | ||
| if (rendered) { | ||
| router.emit({ | ||
| type: 'onRendered', | ||
| ...getLocationChangeInfo(resolvedLocation, resolvedLocation), | ||
| }) | ||
| } | ||
| }, | ||
| ] | ||
| } else if (!router._tx) { | ||
| router.load().catch(console.error) | ||
| } | ||
| mountLoadForRouter.current = { router, mounted: true } | ||
| const tryLoad = async () => { | ||
| try { | ||
| await router.load() | ||
| } catch (err) { | ||
| console.error(err) | ||
| } | ||
| } | ||
| return unsub | ||
| // `mounted` exists only in development and is a stable ref when present. | ||
| // eslint-disable-next-line react-hooks/exhaustive-deps | ||
| }, [router, router.history]) | ||
| tryLoad() | ||
| }, [router]) | ||
| useLayoutEffect(() => { | ||
| // The router was loading and now it's not | ||
| if (previousIsLoading && !isLoading) { | ||
| router.emit({ | ||
| type: 'onLoad', // When the new URL has committed, when the new matches have been loaded into state.matches | ||
| ...getLocationChangeInfo( | ||
| router.stores.location.get(), | ||
| router.stores.resolvedLocation.get(), | ||
| ), | ||
| }) | ||
| } | ||
| }, [previousIsLoading, router, isLoading]) | ||
| useLayoutEffect(() => { | ||
| // emit onBeforeRouteMount | ||
| if (previousIsPagePending && !isPagePending) { | ||
| router.emit({ | ||
| type: 'onBeforeRouteMount', | ||
| ...getLocationChangeInfo( | ||
| router.stores.location.get(), | ||
| router.stores.resolvedLocation.get(), | ||
| ), | ||
| }) | ||
| } | ||
| }, [isPagePending, previousIsPagePending, router]) | ||
| useLayoutEffect(() => { | ||
| if (previousIsAnyPending && !isAnyPending) { | ||
| const changeInfo = getLocationChangeInfo( | ||
| router.stores.location.get(), | ||
| router.stores.resolvedLocation.get(), | ||
| ) | ||
| router.emit({ | ||
| type: 'onResolved', | ||
| ...changeInfo, | ||
| }) | ||
| batch(() => { | ||
| router.stores.status.set('idle') | ||
| router.stores.resolvedLocation.set(router.stores.location.get()) | ||
| }) | ||
| } | ||
| }, [isAnyPending, previousIsAnyPending, router]) | ||
| return null | ||
| } |
+9
-15
@@ -23,8 +23,3 @@ 'use client' | ||
| const dummyStore = { | ||
| get() {}, | ||
| subscribe() { | ||
| return { unsubscribe() {} } | ||
| }, | ||
| } as any | ||
| const dummyMatch = {} | ||
@@ -151,12 +146,11 @@ export function useStructuralSharing< | ||
| const router = useRouter<TRouter>() | ||
| const nearestMatchId = React.useContext( | ||
| const nearestRouteId = React.useContext( | ||
| opts.from ? dummyMatchContext : matchContext, | ||
| ) | ||
| const matchStore = opts.from | ||
| ? router.stores.getRouteMatchStore(opts.from) | ||
| : router.stores.matchStores.get(nearestMatchId!) | ||
| const routeId = opts.from ?? nearestRouteId | ||
| const matchStore = router.stores.getMatchStore(routeId!) | ||
| if (isServer ?? router.isServer) { | ||
| const match = matchStore?.get() | ||
| const match = matchStore.get() | ||
| if (!match) { | ||
@@ -184,8 +178,8 @@ if (opts.shouldThrow ?? true) { | ||
| // eslint-disable-next-line react-hooks/rules-of-hooks -- condition is static | ||
| const matchSelection = useStore(matchStore ?? dummyStore, (match) => | ||
| match ? selector(match as any) : dummyStore, | ||
| const matchSelection = useStore(matchStore, (match) => | ||
| match ? selector(match as any) : dummyMatch, | ||
| ) | ||
| if (matchSelection !== dummyStore) { | ||
| return matchSelection | ||
| if (matchSelection !== dummyMatch) { | ||
| return matchSelection as any | ||
| } | ||
@@ -192,0 +186,0 @@ |
+4
-1
| 'use client' | ||
| import * as React from 'react' | ||
| import { isServer } from '@tanstack/router-core/isServer' | ||
@@ -30,3 +31,5 @@ // Safe version of React.use() that will not cause compilation errors against | ||
| export const useLayoutEffect = | ||
| typeof window !== 'undefined' ? React.useLayoutEffect : React.useEffect | ||
| (isServer ?? typeof window === 'undefined') | ||
| ? React.useEffect | ||
| : React.useLayoutEffect | ||
@@ -33,0 +36,0 @@ /** |
AI-detected potential code anomaly
Supply chain riskAI has identified unusual behaviors that may pose a security risk.
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
AI-detected potential code anomaly
Supply chain riskAI has identified unusual behaviors that may pose a security risk.
62
-25.3%1051876
-7.96%10
11.11%13745
-7.81%2
100%+ Added
- Removed