@tanstack/react-router 1.147.2 → 1.147.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/HeadContent.cjs +3 -201
- package/dist/cjs/HeadContent.cjs.map +1 -1
- package/dist/cjs/HeadContent.d.cts +0 -6
- package/dist/cjs/HeadContent.dev.cjs +41 -0
- package/dist/cjs/HeadContent.dev.cjs.map +1 -0
- package/dist/cjs/HeadContent.dev.d.cts +10 -0
- package/dist/cjs/headContentUtils.cjs +185 -0
- package/dist/cjs/headContentUtils.cjs.map +1 -0
- package/dist/cjs/headContentUtils.d.cts +7 -0
- package/dist/cjs/index.cjs +2 -0
- package/dist/cjs/index.cjs.map +1 -1
- package/dist/cjs/index.d.cts +1 -0
- package/dist/cjs/index.dev.cjs +264 -0
- package/dist/cjs/index.dev.cjs.map +1 -0
- package/dist/cjs/index.dev.d.cts +2 -0
- package/dist/esm/HeadContent.d.ts +0 -6
- package/dist/esm/HeadContent.dev.d.ts +10 -0
- package/dist/esm/HeadContent.dev.js +25 -0
- package/dist/esm/HeadContent.dev.js.map +1 -0
- package/dist/esm/HeadContent.js +4 -186
- package/dist/esm/HeadContent.js.map +1 -1
- package/dist/esm/headContentUtils.d.ts +7 -0
- package/dist/esm/headContentUtils.js +168 -0
- package/dist/esm/headContentUtils.js.map +1 -0
- package/dist/esm/index.d.ts +1 -0
- package/dist/esm/index.dev.d.ts +2 -0
- package/dist/esm/index.dev.js +144 -0
- package/dist/esm/index.dev.js.map +1 -0
- package/dist/esm/index.js +3 -1
- package/dist/esm/index.js.map +1 -1
- package/package.json +5 -3
- package/src/HeadContent.dev.tsx +46 -0
- package/src/HeadContent.tsx +1 -245
- package/src/headContentUtils.tsx +217 -0
- package/src/index.dev.tsx +6 -0
- package/src/index.tsx +1 -0
package/dist/cjs/HeadContent.cjs
CHANGED
|
@@ -2,212 +2,14 @@
|
|
|
2
2
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
3
|
const jsxRuntime = require("react/jsx-runtime");
|
|
4
4
|
const React = require("react");
|
|
5
|
-
const routerCore = require("@tanstack/router-core");
|
|
6
5
|
const Asset = require("./Asset.cjs");
|
|
7
6
|
const useRouter = require("./useRouter.cjs");
|
|
8
|
-
const
|
|
9
|
-
function _interopNamespaceDefault(e) {
|
|
10
|
-
const n = Object.create(null, { [Symbol.toStringTag]: { value: "Module" } });
|
|
11
|
-
if (e) {
|
|
12
|
-
for (const k in e) {
|
|
13
|
-
if (k !== "default") {
|
|
14
|
-
const d = Object.getOwnPropertyDescriptor(e, k);
|
|
15
|
-
Object.defineProperty(n, k, d.get ? d : {
|
|
16
|
-
enumerable: true,
|
|
17
|
-
get: () => e[k]
|
|
18
|
-
});
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
|
-
}
|
|
22
|
-
n.default = e;
|
|
23
|
-
return Object.freeze(n);
|
|
24
|
-
}
|
|
25
|
-
const React__namespace = /* @__PURE__ */ _interopNamespaceDefault(React);
|
|
26
|
-
const useTags = () => {
|
|
27
|
-
const router = useRouter.useRouter();
|
|
28
|
-
const nonce = router.options.ssr?.nonce;
|
|
29
|
-
const routeMeta = useRouterState.useRouterState({
|
|
30
|
-
select: (state) => {
|
|
31
|
-
return state.matches.map((match) => match.meta).filter(Boolean);
|
|
32
|
-
}
|
|
33
|
-
});
|
|
34
|
-
const meta = React__namespace.useMemo(() => {
|
|
35
|
-
const resultMeta = [];
|
|
36
|
-
const metaByAttribute = {};
|
|
37
|
-
let title;
|
|
38
|
-
for (let i = routeMeta.length - 1; i >= 0; i--) {
|
|
39
|
-
const metas = routeMeta[i];
|
|
40
|
-
for (let j = metas.length - 1; j >= 0; j--) {
|
|
41
|
-
const m = metas[j];
|
|
42
|
-
if (!m) continue;
|
|
43
|
-
if (m.title) {
|
|
44
|
-
if (!title) {
|
|
45
|
-
title = {
|
|
46
|
-
tag: "title",
|
|
47
|
-
children: m.title
|
|
48
|
-
};
|
|
49
|
-
}
|
|
50
|
-
} else if ("script:ld+json" in m) {
|
|
51
|
-
try {
|
|
52
|
-
const json = JSON.stringify(m["script:ld+json"]);
|
|
53
|
-
resultMeta.push({
|
|
54
|
-
tag: "script",
|
|
55
|
-
attrs: {
|
|
56
|
-
type: "application/ld+json"
|
|
57
|
-
},
|
|
58
|
-
children: routerCore.escapeHtml(json)
|
|
59
|
-
});
|
|
60
|
-
} catch {
|
|
61
|
-
}
|
|
62
|
-
} else {
|
|
63
|
-
const attribute = m.name ?? m.property;
|
|
64
|
-
if (attribute) {
|
|
65
|
-
if (metaByAttribute[attribute]) {
|
|
66
|
-
continue;
|
|
67
|
-
} else {
|
|
68
|
-
metaByAttribute[attribute] = true;
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
resultMeta.push({
|
|
72
|
-
tag: "meta",
|
|
73
|
-
attrs: {
|
|
74
|
-
...m,
|
|
75
|
-
nonce
|
|
76
|
-
}
|
|
77
|
-
});
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
if (title) {
|
|
82
|
-
resultMeta.push(title);
|
|
83
|
-
}
|
|
84
|
-
if (nonce) {
|
|
85
|
-
resultMeta.push({
|
|
86
|
-
tag: "meta",
|
|
87
|
-
attrs: {
|
|
88
|
-
property: "csp-nonce",
|
|
89
|
-
content: nonce
|
|
90
|
-
}
|
|
91
|
-
});
|
|
92
|
-
}
|
|
93
|
-
resultMeta.reverse();
|
|
94
|
-
return resultMeta;
|
|
95
|
-
}, [routeMeta, nonce]);
|
|
96
|
-
const links = useRouterState.useRouterState({
|
|
97
|
-
select: (state) => {
|
|
98
|
-
const constructed = state.matches.map((match) => match.links).filter(Boolean).flat(1).map((link) => ({
|
|
99
|
-
tag: "link",
|
|
100
|
-
attrs: {
|
|
101
|
-
...link,
|
|
102
|
-
nonce
|
|
103
|
-
}
|
|
104
|
-
}));
|
|
105
|
-
const manifest = router.ssr?.manifest;
|
|
106
|
-
const assets = state.matches.map((match) => manifest?.routes[match.routeId]?.assets ?? []).filter(Boolean).flat(1).filter((asset) => asset.tag === "link").map(
|
|
107
|
-
(asset) => ({
|
|
108
|
-
tag: "link",
|
|
109
|
-
attrs: {
|
|
110
|
-
...asset.attrs,
|
|
111
|
-
suppressHydrationWarning: true,
|
|
112
|
-
nonce
|
|
113
|
-
}
|
|
114
|
-
})
|
|
115
|
-
);
|
|
116
|
-
return [...constructed, ...assets];
|
|
117
|
-
},
|
|
118
|
-
structuralSharing: true
|
|
119
|
-
});
|
|
120
|
-
const preloadLinks = useRouterState.useRouterState({
|
|
121
|
-
select: (state) => {
|
|
122
|
-
const preloadLinks2 = [];
|
|
123
|
-
state.matches.map((match) => router.looseRoutesById[match.routeId]).forEach(
|
|
124
|
-
(route) => router.ssr?.manifest?.routes[route.id]?.preloads?.filter(Boolean).forEach((preload) => {
|
|
125
|
-
preloadLinks2.push({
|
|
126
|
-
tag: "link",
|
|
127
|
-
attrs: {
|
|
128
|
-
rel: "modulepreload",
|
|
129
|
-
href: preload,
|
|
130
|
-
nonce
|
|
131
|
-
}
|
|
132
|
-
});
|
|
133
|
-
})
|
|
134
|
-
);
|
|
135
|
-
return preloadLinks2;
|
|
136
|
-
},
|
|
137
|
-
structuralSharing: true
|
|
138
|
-
});
|
|
139
|
-
const styles = useRouterState.useRouterState({
|
|
140
|
-
select: (state) => state.matches.map((match) => match.styles).flat(1).filter(Boolean).map(({ children, ...attrs }) => ({
|
|
141
|
-
tag: "style",
|
|
142
|
-
attrs,
|
|
143
|
-
children,
|
|
144
|
-
nonce
|
|
145
|
-
})),
|
|
146
|
-
structuralSharing: true
|
|
147
|
-
});
|
|
148
|
-
const headScripts = useRouterState.useRouterState({
|
|
149
|
-
select: (state) => state.matches.map((match) => match.headScripts).flat(1).filter(Boolean).map(({ children, ...script }) => ({
|
|
150
|
-
tag: "script",
|
|
151
|
-
attrs: {
|
|
152
|
-
...script,
|
|
153
|
-
nonce
|
|
154
|
-
},
|
|
155
|
-
children
|
|
156
|
-
})),
|
|
157
|
-
structuralSharing: true
|
|
158
|
-
});
|
|
159
|
-
return uniqBy(
|
|
160
|
-
[
|
|
161
|
-
...meta,
|
|
162
|
-
...preloadLinks,
|
|
163
|
-
...links,
|
|
164
|
-
...styles,
|
|
165
|
-
...headScripts
|
|
166
|
-
],
|
|
167
|
-
(d) => {
|
|
168
|
-
return JSON.stringify(d);
|
|
169
|
-
}
|
|
170
|
-
);
|
|
171
|
-
};
|
|
172
|
-
function DevStylesLink() {
|
|
173
|
-
const router = useRouter.useRouter();
|
|
174
|
-
const routeIds = useRouterState.useRouterState({
|
|
175
|
-
select: (state) => state.matches.map((match) => match.routeId)
|
|
176
|
-
});
|
|
177
|
-
React__namespace.useEffect(() => {
|
|
178
|
-
document.querySelectorAll("[data-tanstack-start-dev-styles]").forEach((el) => el.remove());
|
|
179
|
-
}, []);
|
|
180
|
-
const href = routerCore.buildDevStylesUrl(router.basepath, routeIds);
|
|
181
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
182
|
-
"link",
|
|
183
|
-
{
|
|
184
|
-
rel: "stylesheet",
|
|
185
|
-
href,
|
|
186
|
-
"data-tanstack-start-dev-styles": true,
|
|
187
|
-
suppressHydrationWarning: true
|
|
188
|
-
}
|
|
189
|
-
);
|
|
190
|
-
}
|
|
7
|
+
const headContentUtils = require("./headContentUtils.cjs");
|
|
191
8
|
function HeadContent() {
|
|
192
|
-
const tags = useTags();
|
|
9
|
+
const tags = headContentUtils.useTags();
|
|
193
10
|
const router = useRouter.useRouter();
|
|
194
11
|
const nonce = router.options.ssr?.nonce;
|
|
195
|
-
return /* @__PURE__ */ jsxRuntime.
|
|
196
|
-
process.env.NODE_ENV !== "production" && /* @__PURE__ */ jsxRuntime.jsx(DevStylesLink, {}),
|
|
197
|
-
tags.map((tag) => /* @__PURE__ */ React.createElement(Asset.Asset, { ...tag, key: `tsr-meta-${JSON.stringify(tag)}`, nonce }))
|
|
198
|
-
] });
|
|
199
|
-
}
|
|
200
|
-
function uniqBy(arr, fn) {
|
|
201
|
-
const seen = /* @__PURE__ */ new Set();
|
|
202
|
-
return arr.filter((item) => {
|
|
203
|
-
const key = fn(item);
|
|
204
|
-
if (seen.has(key)) {
|
|
205
|
-
return false;
|
|
206
|
-
}
|
|
207
|
-
seen.add(key);
|
|
208
|
-
return true;
|
|
209
|
-
});
|
|
12
|
+
return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: tags.map((tag) => /* @__PURE__ */ React.createElement(Asset.Asset, { ...tag, key: `tsr-meta-${JSON.stringify(tag)}`, nonce })) });
|
|
210
13
|
}
|
|
211
14
|
exports.HeadContent = HeadContent;
|
|
212
|
-
exports.useTags = useTags;
|
|
213
15
|
//# sourceMappingURL=HeadContent.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"HeadContent.cjs","sources":["../../src/HeadContent.tsx"],"sourcesContent":["import * as React from 'react'\nimport { buildDevStylesUrl, escapeHtml } from '@tanstack/router-core'\nimport { Asset } from './Asset'\nimport { useRouter } from './useRouter'\nimport { useRouterState } from './useRouterState'\nimport type { RouterManagedTag } from '@tanstack/router-core'\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 = () => {\n const router = useRouter()\n const nonce = router.options.ssr?.nonce\n const routeMeta = useRouterState({\n select: (state) => {\n return state.matches.map((match) => match.meta!).filter(Boolean)\n },\n })\n\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 const links = useRouterState({\n select: (state) => {\n const constructed = state.matches\n .map((match) => match.links!)\n .filter(Boolean)\n .flat(1)\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\n // These are the assets extracted from the ViteManifest\n // using the `startManifestPlugin`\n const assets = state.matches\n .map((match) => manifest?.routes[match.routeId]?.assets ?? [])\n .filter(Boolean)\n .flat(1)\n .filter((asset) => asset.tag === 'link')\n .map(\n (asset) =>\n ({\n tag: 'link',\n attrs: {\n ...asset.attrs,\n suppressHydrationWarning: true,\n nonce,\n },\n }) satisfies RouterManagedTag,\n )\n\n return [...constructed, ...assets]\n },\n structuralSharing: true as any,\n })\n\n const preloadLinks = useRouterState({\n select: (state) => {\n const preloadLinks: Array<RouterManagedTag> = []\n\n state.matches\n .map((match) => router.looseRoutesById[match.routeId]!)\n .forEach((route) =>\n router.ssr?.manifest?.routes[route.id]?.preloads\n ?.filter(Boolean)\n .forEach((preload) => {\n preloadLinks.push({\n tag: 'link',\n attrs: {\n rel: 'modulepreload',\n href: preload,\n nonce,\n },\n })\n }),\n )\n\n return preloadLinks\n },\n structuralSharing: true as any,\n })\n\n const styles = useRouterState({\n select: (state) =>\n (\n state.matches\n .map((match) => match.styles!)\n .flat(1)\n .filter(Boolean) as Array<RouterManagedTag>\n ).map(({ children, ...attrs }) => ({\n tag: 'style',\n attrs,\n children,\n nonce,\n })),\n structuralSharing: true as any,\n })\n\n const headScripts: Array<RouterManagedTag> = useRouterState({\n select: (state) =>\n (\n state.matches\n .map((match) => match.headScripts!)\n .flat(1)\n .filter(Boolean) as Array<RouterManagedTag>\n ).map(({ children, ...script }) => ({\n tag: 'script',\n attrs: {\n ...script,\n nonce,\n },\n children,\n })),\n structuralSharing: true as any,\n })\n\n return uniqBy(\n [\n ...meta,\n ...preloadLinks,\n ...links,\n ...styles,\n ...headScripts,\n ] as Array<RouterManagedTag>,\n (d) => {\n return JSON.stringify(d)\n },\n )\n}\n\n/**\n * Renders a stylesheet link for dev mode CSS collection.\n * On the server, renders the full link with route-scoped CSS URL.\n * On the client, renders the same link to avoid hydration mismatch,\n * then removes it after hydration since Vite's HMR handles CSS updates.\n */\nfunction DevStylesLink() {\n const router = useRouter()\n const routeIds = useRouterState({\n select: (state) => state.matches.map((match) => match.routeId),\n })\n\n React.useEffect(() => {\n // After hydration, remove the SSR-rendered dev styles link\n document\n .querySelectorAll('[data-tanstack-start-dev-styles]')\n .forEach((el) => el.remove())\n }, [])\n\n const href = buildDevStylesUrl(router.basepath, routeIds)\n\n return (\n <link\n rel=\"stylesheet\"\n href={href}\n data-tanstack-start-dev-styles\n suppressHydrationWarning\n />\n )\n}\n\n/**\n * Render route-managed head tags (title, meta, links, styles, head scripts).\n * Place inside the document head of your app shell.\n * @link https://tanstack.com/router/latest/docs/framework/react/guide/document-head-management\n */\nexport function HeadContent() {\n const tags = useTags()\n const router = useRouter()\n const nonce = router.options.ssr?.nonce\n return (\n <>\n {process.env.NODE_ENV !== 'production' && <DevStylesLink />}\n {tags.map((tag) => (\n <Asset {...tag} key={`tsr-meta-${JSON.stringify(tag)}`} nonce={nonce} />\n ))}\n </>\n )\n}\n\nfunction uniqBy<T>(arr: Array<T>, fn: (item: T) => string) {\n const seen = new Set<string>()\n return arr.filter((item) => {\n const key = fn(item)\n if (seen.has(key)) {\n return false\n }\n seen.add(key)\n return true\n })\n}\n"],"names":["useRouter","useRouterState","React","escapeHtml","preloadLinks","buildDevStylesUrl","jsx","jsxs","Fragment","createElement","Asset"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"HeadContent.cjs","sources":["../../src/HeadContent.tsx"],"sourcesContent":["import * as React from 'react'\nimport { Asset } from './Asset'\nimport { useRouter } from './useRouter'\nimport { useTags } from './headContentUtils'\n\n/**\n * Render route-managed head tags (title, meta, links, styles, head scripts).\n * Place inside the document head of your app shell.\n * @link https://tanstack.com/router/latest/docs/framework/react/guide/document-head-management\n */\nexport function HeadContent() {\n const tags = useTags()\n const router = useRouter()\n const nonce = router.options.ssr?.nonce\n return (\n <>\n {tags.map((tag) => (\n <Asset {...tag} key={`tsr-meta-${JSON.stringify(tag)}`} nonce={nonce} />\n ))}\n </>\n )\n}\n"],"names":["useTags","useRouter","createElement","Asset"],"mappings":";;;;;;;AAUO,SAAS,cAAc;AAC5B,QAAM,OAAOA,iBAAAA,QAAA;AACb,QAAM,SAASC,UAAAA,UAAA;AACf,QAAM,QAAQ,OAAO,QAAQ,KAAK;AAClC,+DAEK,UAAA,KAAK,IAAI,CAAC,QACTC,oCAACC,MAAAA,SAAO,GAAG,KAAK,KAAK,YAAY,KAAK,UAAU,GAAG,CAAC,IAAI,OAAc,CACvE,GACH;AAEJ;;"}
|
|
@@ -1,9 +1,3 @@
|
|
|
1
|
-
import { RouterManagedTag } from '@tanstack/router-core';
|
|
2
|
-
/**
|
|
3
|
-
* Build the list of head/link/meta/script tags to render for active matches.
|
|
4
|
-
* Used internally by `HeadContent`.
|
|
5
|
-
*/
|
|
6
|
-
export declare const useTags: () => RouterManagedTag[];
|
|
7
1
|
/**
|
|
8
2
|
* Render route-managed head tags (title, meta, links, styles, head scripts).
|
|
9
3
|
* Place inside the document head of your app shell.
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
|
+
const jsxRuntime = require("react/jsx-runtime");
|
|
4
|
+
const React = require("react");
|
|
5
|
+
const Asset = require("./Asset.cjs");
|
|
6
|
+
const useRouter = require("./useRouter.cjs");
|
|
7
|
+
const ClientOnly = require("./ClientOnly.cjs");
|
|
8
|
+
const headContentUtils = require("./headContentUtils.cjs");
|
|
9
|
+
function _interopNamespaceDefault(e) {
|
|
10
|
+
const n = Object.create(null, { [Symbol.toStringTag]: { value: "Module" } });
|
|
11
|
+
if (e) {
|
|
12
|
+
for (const k in e) {
|
|
13
|
+
if (k !== "default") {
|
|
14
|
+
const d = Object.getOwnPropertyDescriptor(e, k);
|
|
15
|
+
Object.defineProperty(n, k, d.get ? d : {
|
|
16
|
+
enumerable: true,
|
|
17
|
+
get: () => e[k]
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
n.default = e;
|
|
23
|
+
return Object.freeze(n);
|
|
24
|
+
}
|
|
25
|
+
const React__namespace = /* @__PURE__ */ _interopNamespaceDefault(React);
|
|
26
|
+
const DEV_STYLES_ATTR = "data-tanstack-router-dev-styles";
|
|
27
|
+
function HeadContent() {
|
|
28
|
+
const tags = headContentUtils.useTags();
|
|
29
|
+
const router = useRouter.useRouter();
|
|
30
|
+
const nonce = router.options.ssr?.nonce;
|
|
31
|
+
const hydrated = ClientOnly.useHydrated();
|
|
32
|
+
React__namespace.useEffect(() => {
|
|
33
|
+
if (hydrated) {
|
|
34
|
+
document.querySelectorAll(`link[${DEV_STYLES_ATTR}]`).forEach((el) => el.remove());
|
|
35
|
+
}
|
|
36
|
+
}, [hydrated]);
|
|
37
|
+
const filteredTags = hydrated ? tags.filter((tag) => !tag.attrs?.[DEV_STYLES_ATTR]) : tags;
|
|
38
|
+
return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: filteredTags.map((tag) => /* @__PURE__ */ React.createElement(Asset.Asset, { ...tag, key: `tsr-meta-${JSON.stringify(tag)}`, nonce })) });
|
|
39
|
+
}
|
|
40
|
+
exports.HeadContent = HeadContent;
|
|
41
|
+
//# sourceMappingURL=HeadContent.dev.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"HeadContent.dev.cjs","sources":["../../src/HeadContent.dev.tsx"],"sourcesContent":["import * as React from 'react'\nimport { Asset } from './Asset'\nimport { useRouter } from './useRouter'\nimport { useHydrated } from './ClientOnly'\nimport { useTags } from './headContentUtils'\n\nconst DEV_STYLES_ATTR = 'data-tanstack-router-dev-styles'\n\n/**\n * Render route-managed head tags (title, meta, links, styles, head scripts).\n * Place inside the document head of your app shell.\n *\n * Development version: filters out dev styles link after hydration and\n * includes a fallback cleanup effect for hydration mismatch cases.\n *\n * @link https://tanstack.com/router/latest/docs/framework/react/guide/document-head-management\n */\nexport function HeadContent() {\n const tags = useTags()\n const router = useRouter()\n const nonce = router.options.ssr?.nonce\n const hydrated = useHydrated()\n\n // Fallback cleanup for hydration mismatch cases\n // Runs when hydration completes to remove any orphaned dev styles links from DOM\n React.useEffect(() => {\n if (hydrated) {\n document\n .querySelectorAll(`link[${DEV_STYLES_ATTR}]`)\n .forEach((el) => el.remove())\n }\n }, [hydrated])\n\n // Filter out dev styles after hydration\n const filteredTags = hydrated\n ? tags.filter((tag) => !tag.attrs?.[DEV_STYLES_ATTR])\n : tags\n\n return (\n <>\n {filteredTags.map((tag) => (\n <Asset {...tag} key={`tsr-meta-${JSON.stringify(tag)}`} nonce={nonce} />\n ))}\n </>\n )\n}\n"],"names":["useTags","useRouter","useHydrated","React","createElement","Asset"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;AAMA,MAAM,kBAAkB;AAWjB,SAAS,cAAc;AAC5B,QAAM,OAAOA,iBAAAA,QAAA;AACb,QAAM,SAASC,UAAAA,UAAA;AACf,QAAM,QAAQ,OAAO,QAAQ,KAAK;AAClC,QAAM,WAAWC,WAAAA,YAAA;AAIjBC,mBAAM,UAAU,MAAM;AACpB,QAAI,UAAU;AACZ,eACG,iBAAiB,QAAQ,eAAe,GAAG,EAC3C,QAAQ,CAAC,OAAO,GAAG,OAAA,CAAQ;AAAA,IAChC;AAAA,EACF,GAAG,CAAC,QAAQ,CAAC;AAGb,QAAM,eAAe,WACjB,KAAK,OAAO,CAAC,QAAQ,CAAC,IAAI,QAAQ,eAAe,CAAC,IAClD;AAEJ,+DAEK,UAAA,aAAa,IAAI,CAAC,QACjBC,oCAACC,MAAAA,SAAO,GAAG,KAAK,KAAK,YAAY,KAAK,UAAU,GAAG,CAAC,IAAI,OAAc,CACvE,GACH;AAEJ;;"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Render route-managed head tags (title, meta, links, styles, head scripts).
|
|
3
|
+
* Place inside the document head of your app shell.
|
|
4
|
+
*
|
|
5
|
+
* Development version: filters out dev styles link after hydration and
|
|
6
|
+
* includes a fallback cleanup effect for hydration mismatch cases.
|
|
7
|
+
*
|
|
8
|
+
* @link https://tanstack.com/router/latest/docs/framework/react/guide/document-head-management
|
|
9
|
+
*/
|
|
10
|
+
export declare function HeadContent(): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
|
+
const React = require("react");
|
|
4
|
+
const routerCore = require("@tanstack/router-core");
|
|
5
|
+
const useRouter = require("./useRouter.cjs");
|
|
6
|
+
const useRouterState = require("./useRouterState.cjs");
|
|
7
|
+
function _interopNamespaceDefault(e) {
|
|
8
|
+
const n = Object.create(null, { [Symbol.toStringTag]: { value: "Module" } });
|
|
9
|
+
if (e) {
|
|
10
|
+
for (const k in e) {
|
|
11
|
+
if (k !== "default") {
|
|
12
|
+
const d = Object.getOwnPropertyDescriptor(e, k);
|
|
13
|
+
Object.defineProperty(n, k, d.get ? d : {
|
|
14
|
+
enumerable: true,
|
|
15
|
+
get: () => e[k]
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
n.default = e;
|
|
21
|
+
return Object.freeze(n);
|
|
22
|
+
}
|
|
23
|
+
const React__namespace = /* @__PURE__ */ _interopNamespaceDefault(React);
|
|
24
|
+
const useTags = () => {
|
|
25
|
+
const router = useRouter.useRouter();
|
|
26
|
+
const nonce = router.options.ssr?.nonce;
|
|
27
|
+
const routeMeta = useRouterState.useRouterState({
|
|
28
|
+
select: (state) => {
|
|
29
|
+
return state.matches.map((match) => match.meta).filter(Boolean);
|
|
30
|
+
}
|
|
31
|
+
});
|
|
32
|
+
const meta = React__namespace.useMemo(() => {
|
|
33
|
+
const resultMeta = [];
|
|
34
|
+
const metaByAttribute = {};
|
|
35
|
+
let title;
|
|
36
|
+
for (let i = routeMeta.length - 1; i >= 0; i--) {
|
|
37
|
+
const metas = routeMeta[i];
|
|
38
|
+
for (let j = metas.length - 1; j >= 0; j--) {
|
|
39
|
+
const m = metas[j];
|
|
40
|
+
if (!m) continue;
|
|
41
|
+
if (m.title) {
|
|
42
|
+
if (!title) {
|
|
43
|
+
title = {
|
|
44
|
+
tag: "title",
|
|
45
|
+
children: m.title
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
} else if ("script:ld+json" in m) {
|
|
49
|
+
try {
|
|
50
|
+
const json = JSON.stringify(m["script:ld+json"]);
|
|
51
|
+
resultMeta.push({
|
|
52
|
+
tag: "script",
|
|
53
|
+
attrs: {
|
|
54
|
+
type: "application/ld+json"
|
|
55
|
+
},
|
|
56
|
+
children: routerCore.escapeHtml(json)
|
|
57
|
+
});
|
|
58
|
+
} catch {
|
|
59
|
+
}
|
|
60
|
+
} else {
|
|
61
|
+
const attribute = m.name ?? m.property;
|
|
62
|
+
if (attribute) {
|
|
63
|
+
if (metaByAttribute[attribute]) {
|
|
64
|
+
continue;
|
|
65
|
+
} else {
|
|
66
|
+
metaByAttribute[attribute] = true;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
resultMeta.push({
|
|
70
|
+
tag: "meta",
|
|
71
|
+
attrs: {
|
|
72
|
+
...m,
|
|
73
|
+
nonce
|
|
74
|
+
}
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
if (title) {
|
|
80
|
+
resultMeta.push(title);
|
|
81
|
+
}
|
|
82
|
+
if (nonce) {
|
|
83
|
+
resultMeta.push({
|
|
84
|
+
tag: "meta",
|
|
85
|
+
attrs: {
|
|
86
|
+
property: "csp-nonce",
|
|
87
|
+
content: nonce
|
|
88
|
+
}
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
resultMeta.reverse();
|
|
92
|
+
return resultMeta;
|
|
93
|
+
}, [routeMeta, nonce]);
|
|
94
|
+
const links = useRouterState.useRouterState({
|
|
95
|
+
select: (state) => {
|
|
96
|
+
const constructed = state.matches.map((match) => match.links).filter(Boolean).flat(1).map((link) => ({
|
|
97
|
+
tag: "link",
|
|
98
|
+
attrs: {
|
|
99
|
+
...link,
|
|
100
|
+
nonce
|
|
101
|
+
}
|
|
102
|
+
}));
|
|
103
|
+
const manifest = router.ssr?.manifest;
|
|
104
|
+
const assets = state.matches.map((match) => manifest?.routes[match.routeId]?.assets ?? []).filter(Boolean).flat(1).filter((asset) => asset.tag === "link").map(
|
|
105
|
+
(asset) => ({
|
|
106
|
+
tag: "link",
|
|
107
|
+
attrs: {
|
|
108
|
+
...asset.attrs,
|
|
109
|
+
suppressHydrationWarning: true,
|
|
110
|
+
nonce
|
|
111
|
+
}
|
|
112
|
+
})
|
|
113
|
+
);
|
|
114
|
+
return [...constructed, ...assets];
|
|
115
|
+
},
|
|
116
|
+
structuralSharing: true
|
|
117
|
+
});
|
|
118
|
+
const preloadLinks = useRouterState.useRouterState({
|
|
119
|
+
select: (state) => {
|
|
120
|
+
const preloadLinks2 = [];
|
|
121
|
+
state.matches.map((match) => router.looseRoutesById[match.routeId]).forEach(
|
|
122
|
+
(route) => router.ssr?.manifest?.routes[route.id]?.preloads?.filter(Boolean).forEach((preload) => {
|
|
123
|
+
preloadLinks2.push({
|
|
124
|
+
tag: "link",
|
|
125
|
+
attrs: {
|
|
126
|
+
rel: "modulepreload",
|
|
127
|
+
href: preload,
|
|
128
|
+
nonce
|
|
129
|
+
}
|
|
130
|
+
});
|
|
131
|
+
})
|
|
132
|
+
);
|
|
133
|
+
return preloadLinks2;
|
|
134
|
+
},
|
|
135
|
+
structuralSharing: true
|
|
136
|
+
});
|
|
137
|
+
const styles = useRouterState.useRouterState({
|
|
138
|
+
select: (state) => state.matches.map((match) => match.styles).flat(1).filter(Boolean).map(({ children, ...attrs }) => ({
|
|
139
|
+
tag: "style",
|
|
140
|
+
attrs: {
|
|
141
|
+
...attrs,
|
|
142
|
+
nonce
|
|
143
|
+
},
|
|
144
|
+
children
|
|
145
|
+
})),
|
|
146
|
+
structuralSharing: true
|
|
147
|
+
});
|
|
148
|
+
const headScripts = useRouterState.useRouterState({
|
|
149
|
+
select: (state) => state.matches.map((match) => match.headScripts).flat(1).filter(Boolean).map(({ children, ...script }) => ({
|
|
150
|
+
tag: "script",
|
|
151
|
+
attrs: {
|
|
152
|
+
...script,
|
|
153
|
+
nonce
|
|
154
|
+
},
|
|
155
|
+
children
|
|
156
|
+
})),
|
|
157
|
+
structuralSharing: true
|
|
158
|
+
});
|
|
159
|
+
return uniqBy(
|
|
160
|
+
[
|
|
161
|
+
...meta,
|
|
162
|
+
...preloadLinks,
|
|
163
|
+
...links,
|
|
164
|
+
...styles,
|
|
165
|
+
...headScripts
|
|
166
|
+
],
|
|
167
|
+
(d) => {
|
|
168
|
+
return JSON.stringify(d);
|
|
169
|
+
}
|
|
170
|
+
);
|
|
171
|
+
};
|
|
172
|
+
function uniqBy(arr, fn) {
|
|
173
|
+
const seen = /* @__PURE__ */ new Set();
|
|
174
|
+
return arr.filter((item) => {
|
|
175
|
+
const key = fn(item);
|
|
176
|
+
if (seen.has(key)) {
|
|
177
|
+
return false;
|
|
178
|
+
}
|
|
179
|
+
seen.add(key);
|
|
180
|
+
return true;
|
|
181
|
+
});
|
|
182
|
+
}
|
|
183
|
+
exports.uniqBy = uniqBy;
|
|
184
|
+
exports.useTags = useTags;
|
|
185
|
+
//# sourceMappingURL=headContentUtils.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"headContentUtils.cjs","sources":["../../src/headContentUtils.tsx"],"sourcesContent":["import * as React from 'react'\nimport { escapeHtml } from '@tanstack/router-core'\nimport { useRouter } from './useRouter'\nimport { useRouterState } from './useRouterState'\nimport type { RouterManagedTag } from '@tanstack/router-core'\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 = () => {\n const router = useRouter()\n const nonce = router.options.ssr?.nonce\n const routeMeta = useRouterState({\n select: (state) => {\n return state.matches.map((match) => match.meta!).filter(Boolean)\n },\n })\n\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 const links = useRouterState({\n select: (state) => {\n const constructed = state.matches\n .map((match) => match.links!)\n .filter(Boolean)\n .flat(1)\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\n // These are the assets extracted from the ViteManifest\n // using the `startManifestPlugin`\n const assets = state.matches\n .map((match) => manifest?.routes[match.routeId]?.assets ?? [])\n .filter(Boolean)\n .flat(1)\n .filter((asset) => asset.tag === 'link')\n .map(\n (asset) =>\n ({\n tag: 'link',\n attrs: {\n ...asset.attrs,\n suppressHydrationWarning: true,\n nonce,\n },\n }) satisfies RouterManagedTag,\n )\n\n return [...constructed, ...assets]\n },\n structuralSharing: true as any,\n })\n\n const preloadLinks = useRouterState({\n select: (state) => {\n const preloadLinks: Array<RouterManagedTag> = []\n\n state.matches\n .map((match) => router.looseRoutesById[match.routeId]!)\n .forEach((route) =>\n router.ssr?.manifest?.routes[route.id]?.preloads\n ?.filter(Boolean)\n .forEach((preload) => {\n preloadLinks.push({\n tag: 'link',\n attrs: {\n rel: 'modulepreload',\n href: preload,\n nonce,\n },\n })\n }),\n )\n\n return preloadLinks\n },\n structuralSharing: true as any,\n })\n\n const styles = useRouterState({\n select: (state) =>\n (\n state.matches\n .map((match) => match.styles!)\n .flat(1)\n .filter(Boolean) as Array<RouterManagedTag>\n ).map(({ children, ...attrs }) => ({\n tag: 'style',\n attrs: {\n ...attrs,\n nonce,\n },\n children,\n })),\n structuralSharing: true as any,\n })\n\n const headScripts: Array<RouterManagedTag> = useRouterState({\n select: (state) =>\n (\n state.matches\n .map((match) => match.headScripts!)\n .flat(1)\n .filter(Boolean) as Array<RouterManagedTag>\n ).map(({ children, ...script }) => ({\n tag: 'script',\n attrs: {\n ...script,\n nonce,\n },\n children,\n })),\n structuralSharing: true as any,\n })\n\n return uniqBy(\n [\n ...meta,\n ...preloadLinks,\n ...links,\n ...styles,\n ...headScripts,\n ] as Array<RouterManagedTag>,\n (d) => {\n return JSON.stringify(d)\n },\n )\n}\n\nexport function uniqBy<T>(arr: Array<T>, fn: (item: T) => string) {\n const seen = new Set<string>()\n return arr.filter((item) => {\n const key = fn(item)\n if (seen.has(key)) {\n return false\n }\n seen.add(key)\n return true\n })\n}\n"],"names":["useRouter","useRouterState","React","escapeHtml","preloadLinks"],"mappings":"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"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { RouterManagedTag } from '@tanstack/router-core';
|
|
2
|
+
/**
|
|
3
|
+
* Build the list of head/link/meta/script tags to render for active matches.
|
|
4
|
+
* Used internally by `HeadContent`.
|
|
5
|
+
*/
|
|
6
|
+
export declare const useTags: () => RouterManagedTag[];
|
|
7
|
+
export declare function uniqBy<T>(arr: Array<T>, fn: (item: T) => string): T[];
|
package/dist/cjs/index.cjs
CHANGED
|
@@ -33,6 +33,7 @@ const notFound = require("./not-found.cjs");
|
|
|
33
33
|
const ScriptOnce = require("./ScriptOnce.cjs");
|
|
34
34
|
const Asset = require("./Asset.cjs");
|
|
35
35
|
const HeadContent = require("./HeadContent.cjs");
|
|
36
|
+
const headContentUtils = require("./headContentUtils.cjs");
|
|
36
37
|
const Scripts = require("./Scripts.cjs");
|
|
37
38
|
Object.defineProperty(exports, "PathParamError", {
|
|
38
39
|
enumerable: true,
|
|
@@ -258,5 +259,6 @@ exports.DefaultGlobalNotFound = notFound.DefaultGlobalNotFound;
|
|
|
258
259
|
exports.ScriptOnce = ScriptOnce.ScriptOnce;
|
|
259
260
|
exports.Asset = Asset.Asset;
|
|
260
261
|
exports.HeadContent = HeadContent.HeadContent;
|
|
262
|
+
exports.useTags = headContentUtils.useTags;
|
|
261
263
|
exports.Scripts = Scripts.Scripts;
|
|
262
264
|
//# sourceMappingURL=index.cjs.map
|
package/dist/cjs/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.cjs","sources":[],"sourcesContent":[],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.cjs","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
|
package/dist/cjs/index.d.cts
CHANGED
|
@@ -48,6 +48,7 @@ export type { ValidateFromPath, ValidateToPath, ValidateSearch, ValidateParams,
|
|
|
48
48
|
export { ScriptOnce } from './ScriptOnce.cjs';
|
|
49
49
|
export { Asset } from './Asset.cjs';
|
|
50
50
|
export { HeadContent } from './HeadContent.cjs';
|
|
51
|
+
export { useTags } from './headContentUtils.cjs';
|
|
51
52
|
export { Scripts } from './Scripts.cjs';
|
|
52
53
|
export type * from './ssr/serializer.cjs';
|
|
53
54
|
export { composeRewrites } from '@tanstack/router-core';
|