@tanstack/solid-router 1.147.1 → 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 +5 -196
- package/dist/cjs/HeadContent.cjs.map +1 -1
- package/dist/cjs/HeadContent.d.cts +1 -4
- package/dist/cjs/HeadContent.dev.cjs +36 -0
- package/dist/cjs/HeadContent.dev.cjs.map +1 -0
- package/dist/cjs/HeadContent.dev.d.cts +10 -0
- package/dist/cjs/headContentUtils.cjs +174 -0
- package/dist/cjs/headContentUtils.cjs.map +1 -0
- package/dist/cjs/headContentUtils.d.cts +7 -0
- package/dist/cjs/index.cjs +2 -1
- package/dist/cjs/index.cjs.map +1 -1
- package/dist/cjs/index.d.cts +2 -1
- package/dist/cjs/index.dev.cjs +259 -0
- package/dist/cjs/index.dev.cjs.map +1 -0
- package/dist/cjs/index.dev.d.cts +2 -0
- package/dist/cjs/ssr/RouterServer.cjs +2 -2
- package/dist/cjs/ssr/RouterServer.cjs.map +1 -1
- package/dist/esm/HeadContent.d.ts +1 -4
- package/dist/esm/HeadContent.dev.d.ts +10 -0
- package/dist/esm/HeadContent.dev.js +36 -0
- package/dist/esm/HeadContent.dev.js.map +1 -0
- package/dist/esm/HeadContent.js +6 -181
- package/dist/esm/HeadContent.js.map +1 -1
- package/dist/esm/headContentUtils.d.ts +7 -0
- package/dist/esm/headContentUtils.js +157 -0
- package/dist/esm/headContentUtils.js.map +1 -0
- package/dist/esm/index.d.ts +2 -1
- package/dist/esm/index.dev.d.ts +2 -0
- package/dist/esm/index.dev.js +142 -0
- package/dist/esm/index.dev.js.map +1 -0
- package/dist/esm/index.js +2 -1
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/ssr/RouterServer.js +1 -1
- package/dist/esm/ssr/RouterServer.js.map +1 -1
- package/dist/source/HeadContent.d.ts +1 -4
- package/dist/source/HeadContent.dev.d.ts +10 -0
- package/dist/source/HeadContent.dev.jsx +39 -0
- package/dist/source/HeadContent.dev.jsx.map +1 -0
- package/dist/source/HeadContent.jsx +2 -202
- package/dist/source/HeadContent.jsx.map +1 -1
- package/dist/source/headContentUtils.d.ts +7 -0
- package/dist/source/headContentUtils.jsx +181 -0
- package/dist/source/headContentUtils.jsx.map +1 -0
- package/dist/source/index.d.ts +2 -1
- package/dist/source/index.dev.d.ts +2 -0
- package/dist/source/index.dev.jsx +6 -0
- package/dist/source/index.dev.jsx.map +1 -0
- package/dist/source/index.jsx +2 -1
- package/dist/source/index.jsx.map +1 -1
- package/dist/source/ssr/RouterServer.jsx +1 -1
- package/dist/source/ssr/RouterServer.jsx.map +1 -1
- package/package.json +4 -1
- package/src/HeadContent.dev.tsx +45 -0
- package/src/HeadContent.tsx +2 -235
- package/src/headContentUtils.tsx +209 -0
- package/src/index.dev.tsx +6 -0
- package/src/index.tsx +2 -1
- package/src/ssr/RouterServer.tsx +1 -1
package/dist/cjs/HeadContent.cjs
CHANGED
|
@@ -1,213 +1,22 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
3
|
const Solid = require("solid-js/web");
|
|
4
|
-
const Solid$1 = require("solid-js");
|
|
5
4
|
const meta = require("@solidjs/meta");
|
|
6
|
-
const
|
|
5
|
+
const Solid$1 = require("solid-js");
|
|
7
6
|
const Asset = require("./Asset.cjs");
|
|
8
|
-
const
|
|
9
|
-
const useRouterState = require("./useRouterState.cjs");
|
|
10
|
-
function _interopNamespaceDefault(e) {
|
|
11
|
-
const n = Object.create(null, { [Symbol.toStringTag]: { value: "Module" } });
|
|
12
|
-
if (e) {
|
|
13
|
-
for (const k in e) {
|
|
14
|
-
if (k !== "default") {
|
|
15
|
-
const d = Object.getOwnPropertyDescriptor(e, k);
|
|
16
|
-
Object.defineProperty(n, k, d.get ? d : {
|
|
17
|
-
enumerable: true,
|
|
18
|
-
get: () => e[k]
|
|
19
|
-
});
|
|
20
|
-
}
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
|
-
n.default = e;
|
|
24
|
-
return Object.freeze(n);
|
|
25
|
-
}
|
|
26
|
-
const Solid__namespace = /* @__PURE__ */ _interopNamespaceDefault(Solid$1);
|
|
27
|
-
var _tmpl$ = /* @__PURE__ */ Solid.template(`<link rel=stylesheet data-tanstack-start-dev-styles>`);
|
|
28
|
-
const useTags = () => {
|
|
29
|
-
const router = useRouter.useRouter();
|
|
30
|
-
const nonce = router.options.ssr?.nonce;
|
|
31
|
-
const routeMeta = useRouterState.useRouterState({
|
|
32
|
-
select: (state) => {
|
|
33
|
-
return state.matches.map((match) => match.meta).filter(Boolean);
|
|
34
|
-
}
|
|
35
|
-
});
|
|
36
|
-
const meta2 = Solid__namespace.createMemo(() => {
|
|
37
|
-
const resultMeta = [];
|
|
38
|
-
const metaByAttribute = {};
|
|
39
|
-
let title;
|
|
40
|
-
const routeMetasArray = routeMeta();
|
|
41
|
-
for (let i = routeMetasArray.length - 1; i >= 0; i--) {
|
|
42
|
-
const metas = routeMetasArray[i];
|
|
43
|
-
for (let j = metas.length - 1; j >= 0; j--) {
|
|
44
|
-
const m = metas[j];
|
|
45
|
-
if (!m) continue;
|
|
46
|
-
if (m.title) {
|
|
47
|
-
if (!title) {
|
|
48
|
-
title = {
|
|
49
|
-
tag: "title",
|
|
50
|
-
children: m.title
|
|
51
|
-
};
|
|
52
|
-
}
|
|
53
|
-
} else if ("script:ld+json" in m) {
|
|
54
|
-
try {
|
|
55
|
-
const json = JSON.stringify(m["script:ld+json"]);
|
|
56
|
-
resultMeta.push({
|
|
57
|
-
tag: "script",
|
|
58
|
-
attrs: {
|
|
59
|
-
type: "application/ld+json"
|
|
60
|
-
},
|
|
61
|
-
children: routerCore.escapeHtml(json)
|
|
62
|
-
});
|
|
63
|
-
} catch {
|
|
64
|
-
}
|
|
65
|
-
} else {
|
|
66
|
-
const attribute = m.name ?? m.property;
|
|
67
|
-
if (attribute) {
|
|
68
|
-
if (metaByAttribute[attribute]) {
|
|
69
|
-
continue;
|
|
70
|
-
} else {
|
|
71
|
-
metaByAttribute[attribute] = true;
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
resultMeta.push({
|
|
75
|
-
tag: "meta",
|
|
76
|
-
attrs: {
|
|
77
|
-
...m,
|
|
78
|
-
nonce
|
|
79
|
-
}
|
|
80
|
-
});
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
if (title) {
|
|
85
|
-
resultMeta.push(title);
|
|
86
|
-
}
|
|
87
|
-
if (router.options.ssr?.nonce) {
|
|
88
|
-
resultMeta.push({
|
|
89
|
-
tag: "meta",
|
|
90
|
-
attrs: {
|
|
91
|
-
property: "csp-nonce",
|
|
92
|
-
content: router.options.ssr.nonce
|
|
93
|
-
}
|
|
94
|
-
});
|
|
95
|
-
}
|
|
96
|
-
resultMeta.reverse();
|
|
97
|
-
return resultMeta;
|
|
98
|
-
});
|
|
99
|
-
const links = useRouterState.useRouterState({
|
|
100
|
-
select: (state) => {
|
|
101
|
-
const constructed = state.matches.map((match) => match.links).filter(Boolean).flat(1).map((link) => ({
|
|
102
|
-
tag: "link",
|
|
103
|
-
attrs: {
|
|
104
|
-
...link,
|
|
105
|
-
nonce
|
|
106
|
-
}
|
|
107
|
-
}));
|
|
108
|
-
const manifest = router.ssr?.manifest;
|
|
109
|
-
const assets = state.matches.map((match) => manifest?.routes[match.routeId]?.assets ?? []).filter(Boolean).flat(1).filter((asset) => asset.tag === "link").map((asset) => ({
|
|
110
|
-
tag: "link",
|
|
111
|
-
attrs: {
|
|
112
|
-
...asset.attrs,
|
|
113
|
-
nonce
|
|
114
|
-
}
|
|
115
|
-
}));
|
|
116
|
-
return [...constructed, ...assets];
|
|
117
|
-
}
|
|
118
|
-
});
|
|
119
|
-
const preloadLinks = useRouterState.useRouterState({
|
|
120
|
-
select: (state) => {
|
|
121
|
-
const preloadLinks2 = [];
|
|
122
|
-
state.matches.map((match) => router.looseRoutesById[match.routeId]).forEach((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
|
-
return preloadLinks2;
|
|
133
|
-
}
|
|
134
|
-
});
|
|
135
|
-
const styles = useRouterState.useRouterState({
|
|
136
|
-
select: (state) => state.matches.map((match) => match.styles).flat(1).filter(Boolean).map(({
|
|
137
|
-
children,
|
|
138
|
-
...style
|
|
139
|
-
}) => ({
|
|
140
|
-
tag: "style",
|
|
141
|
-
attrs: {
|
|
142
|
-
...style,
|
|
143
|
-
nonce
|
|
144
|
-
},
|
|
145
|
-
children
|
|
146
|
-
}))
|
|
147
|
-
});
|
|
148
|
-
const headScripts = useRouterState.useRouterState({
|
|
149
|
-
select: (state) => state.matches.map((match) => match.headScripts).flat(1).filter(Boolean).map(({
|
|
150
|
-
children,
|
|
151
|
-
...script
|
|
152
|
-
}) => ({
|
|
153
|
-
tag: "script",
|
|
154
|
-
attrs: {
|
|
155
|
-
...script,
|
|
156
|
-
nonce
|
|
157
|
-
},
|
|
158
|
-
children
|
|
159
|
-
}))
|
|
160
|
-
});
|
|
161
|
-
return () => uniqBy([...meta2(), ...preloadLinks(), ...links(), ...styles(), ...headScripts()], (d) => {
|
|
162
|
-
return JSON.stringify(d);
|
|
163
|
-
});
|
|
164
|
-
};
|
|
165
|
-
function DevStylesLink() {
|
|
166
|
-
const router = useRouter.useRouter();
|
|
167
|
-
const routeIds = useRouterState.useRouterState({
|
|
168
|
-
select: (state) => state.matches.map((match) => match.routeId)
|
|
169
|
-
});
|
|
170
|
-
Solid$1.onMount(() => {
|
|
171
|
-
document.querySelectorAll("[data-tanstack-start-dev-styles]").forEach((el) => el.remove());
|
|
172
|
-
});
|
|
173
|
-
const href = () => routerCore.buildDevStylesUrl(router.basepath, routeIds());
|
|
174
|
-
return (() => {
|
|
175
|
-
var _el$ = _tmpl$();
|
|
176
|
-
Solid.effect(() => Solid.setAttribute(_el$, "href", href()));
|
|
177
|
-
return _el$;
|
|
178
|
-
})();
|
|
179
|
-
}
|
|
7
|
+
const headContentUtils = require("./headContentUtils.cjs");
|
|
180
8
|
function HeadContent() {
|
|
181
|
-
const tags = useTags();
|
|
9
|
+
const tags = headContentUtils.useTags();
|
|
182
10
|
return Solid.createComponent(meta.MetaProvider, {
|
|
183
11
|
get children() {
|
|
184
|
-
return
|
|
185
|
-
get when() {
|
|
186
|
-
return process.env.NODE_ENV !== "production";
|
|
187
|
-
},
|
|
188
|
-
get children() {
|
|
189
|
-
return Solid.createComponent(DevStylesLink, {});
|
|
190
|
-
}
|
|
191
|
-
}), Solid.createComponent(Solid$1.For, {
|
|
12
|
+
return Solid.createComponent(Solid$1.For, {
|
|
192
13
|
get each() {
|
|
193
14
|
return tags();
|
|
194
15
|
},
|
|
195
16
|
children: (tag) => Solid.createComponent(Asset.Asset, tag)
|
|
196
|
-
})
|
|
197
|
-
}
|
|
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;
|
|
17
|
+
});
|
|
206
18
|
}
|
|
207
|
-
seen.add(key);
|
|
208
|
-
return true;
|
|
209
19
|
});
|
|
210
20
|
}
|
|
211
21
|
exports.HeadContent = HeadContent;
|
|
212
|
-
exports.useTags = useTags;
|
|
213
22
|
//# sourceMappingURL=HeadContent.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"HeadContent.cjs","sources":["../../src/HeadContent.tsx"],"sourcesContent":["import * as Solid from 'solid-js'\nimport { MetaProvider } from '@solidjs/meta'\nimport { For, Show, onMount } from 'solid-js'\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\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: Solid.Accessor<Array<RouterManagedTag>> = Solid.createMemo(() => {\n const resultMeta: Array<RouterManagedTag> = []\n const metaByAttribute: Record<string, true> = {}\n let title: RouterManagedTag | undefined\n const routeMetasArray = routeMeta()\n for (let i = routeMetasArray.length - 1; i >= 0; i--) {\n const metas = routeMetasArray[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 innerHTML\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 (router.options.ssr?.nonce) {\n resultMeta.push({\n tag: 'meta',\n attrs: {\n property: 'csp-nonce',\n content: router.options.ssr.nonce,\n },\n })\n }\n resultMeta.reverse()\n\n return resultMeta\n })\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: { ...asset.attrs, nonce },\n }) satisfies RouterManagedTag,\n )\n\n return [...constructed, ...assets]\n },\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 })\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, ...style }) => ({\n tag: 'style',\n attrs: {\n ...style,\n nonce,\n },\n children,\n })),\n })\n\n const headScripts = 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 })\n\n return () =>\n 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 onMount(() => {\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 <link rel=\"stylesheet\" href={href()} data-tanstack-start-dev-styles />\n}\n\n/**\n * @description The `HeadContent` component is used to render meta tags, links, and scripts for the current route.\n * When using full document hydration (hydrating from `<html>`), this component should be rendered in the `<body>`\n * to ensure it's part of the reactive tree and updates correctly during client-side navigation.\n * The component uses portals internally to render content into the `<head>` element.\n */\nexport function HeadContent() {\n const tags = useTags()\n\n return (\n <MetaProvider>\n <Show when={process.env.NODE_ENV !== 'production'}>\n <DevStylesLink />\n </Show>\n <For each={tags()}>{(tag) => <Asset {...tag} />}</For>\n </MetaProvider>\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":["useTags","router","useRouter","nonce","options","ssr","routeMeta","useRouterState","select","state","matches","map","match","meta","filter","Boolean","Solid","createMemo","resultMeta","metaByAttribute","title","routeMetasArray","i","length","metas","j","m","tag","children","json","JSON","stringify","push","attrs","type","escapeHtml","attribute","name","property","content","reverse","links","constructed","flat","link","manifest","assets","routes","routeId","asset","preloadLinks","looseRoutesById","forEach","route","id","preloads","preload","rel","href","styles","style","headScripts","script","uniqBy","d","DevStylesLink","routeIds","onMount","document","querySelectorAll","el","remove","buildDevStylesUrl","basepath","_el$","_tmpl$","_$effect","_$setAttribute","HeadContent","tags","_$createComponent","MetaProvider","Show","when","process","env","NODE_ENV","For","each","Asset","arr","fn","seen","Set","item","key","has","add"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"HeadContent.cjs","sources":["../../src/HeadContent.tsx"],"sourcesContent":["import { MetaProvider } from '@solidjs/meta'\nimport { For } from 'solid-js'\nimport { Asset } from './Asset'\nimport { useTags } from './headContentUtils'\n\n/**\n * @description The `HeadContent` component is used to render meta tags, links, and scripts for the current route.\n * When using full document hydration (hydrating from `<html>`), this component should be rendered in the `<body>`\n * to ensure it's part of the reactive tree and updates correctly during client-side navigation.\n * The component uses portals internally to render content into the `<head>` element.\n */\nexport function HeadContent() {\n const tags = useTags()\n\n return (\n <MetaProvider>\n <For each={tags()}>{(tag) => <Asset {...tag} />}</For>\n </MetaProvider>\n )\n}\n"],"names":["HeadContent","tags","useTags","_$createComponent","MetaProvider","children","For","each","tag","Asset"],"mappings":";;;;;;;AAWO,SAASA,cAAc;AAC5B,QAAMC,OAAOC,iBAAAA,QAAAA;AAEb,SAAAC,MAAAA,gBACGC,KAAAA,cAAY;AAAA,IAAA,IAAAC,WAAA;AAAA,aAAAF,MAAAA,gBACVG,QAAAA,KAAG;AAAA,QAAA,IAACC,OAAI;AAAA,iBAAEN,KAAAA;AAAAA,QAAM;AAAA,QAAAI,UAAIG,CAAAA,QAAGL,MAAAA,gBAAMM,MAAAA,OAAUD,GAAG;AAAA,MAAA,CAAI;AAAA,IAAA;AAAA,EAAA,CAAA;AAGrD;;"}
|
|
@@ -1,10 +1,7 @@
|
|
|
1
|
-
import { RouterManagedTag } from '@tanstack/router-core';
|
|
2
|
-
import * as Solid from 'solid-js';
|
|
3
|
-
export declare const useTags: () => () => RouterManagedTag[];
|
|
4
1
|
/**
|
|
5
2
|
* @description The `HeadContent` component is used to render meta tags, links, and scripts for the current route.
|
|
6
3
|
* When using full document hydration (hydrating from `<html>`), this component should be rendered in the `<body>`
|
|
7
4
|
* to ensure it's part of the reactive tree and updates correctly during client-side navigation.
|
|
8
5
|
* The component uses portals internally to render content into the `<head>` element.
|
|
9
6
|
*/
|
|
10
|
-
export declare function HeadContent():
|
|
7
|
+
export declare function HeadContent(): import("solid-js").JSX.Element;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
|
+
const Solid$1 = require("solid-js/web");
|
|
4
|
+
const meta = require("@solidjs/meta");
|
|
5
|
+
const Solid = require("solid-js");
|
|
6
|
+
const Asset = require("./Asset.cjs");
|
|
7
|
+
const ClientOnly = require("./ClientOnly.cjs");
|
|
8
|
+
const headContentUtils = require("./headContentUtils.cjs");
|
|
9
|
+
const DEV_STYLES_ATTR = "data-tanstack-router-dev-styles";
|
|
10
|
+
function HeadContent() {
|
|
11
|
+
const tags = headContentUtils.useTags();
|
|
12
|
+
const hydrated = ClientOnly.useHydrated();
|
|
13
|
+
Solid.createEffect(() => {
|
|
14
|
+
if (hydrated()) {
|
|
15
|
+
document.querySelectorAll(`link[${DEV_STYLES_ATTR}]`).forEach((el) => el.remove());
|
|
16
|
+
}
|
|
17
|
+
});
|
|
18
|
+
const filteredTags = Solid.createMemo(() => {
|
|
19
|
+
if (hydrated()) {
|
|
20
|
+
return tags().filter((tag) => !tag.attrs?.[DEV_STYLES_ATTR]);
|
|
21
|
+
}
|
|
22
|
+
return tags();
|
|
23
|
+
});
|
|
24
|
+
return Solid$1.createComponent(meta.MetaProvider, {
|
|
25
|
+
get children() {
|
|
26
|
+
return Solid$1.createComponent(Solid.For, {
|
|
27
|
+
get each() {
|
|
28
|
+
return filteredTags();
|
|
29
|
+
},
|
|
30
|
+
children: (tag) => Solid$1.createComponent(Asset.Asset, tag)
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
exports.HeadContent = HeadContent;
|
|
36
|
+
//# sourceMappingURL=HeadContent.dev.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"HeadContent.dev.cjs","sources":["../../src/HeadContent.dev.tsx"],"sourcesContent":["import { MetaProvider } from '@solidjs/meta'\nimport { For, createEffect, createMemo } from 'solid-js'\nimport { Asset } from './Asset'\nimport { useHydrated } from './ClientOnly'\nimport { useTags } from './headContentUtils'\n\nconst DEV_STYLES_ATTR = 'data-tanstack-router-dev-styles'\n\n/**\n * @description The `HeadContent` component is used to render meta tags, links, and scripts for the current route.\n * When using full document hydration (hydrating from `<html>`), this component should be rendered in the `<body>`\n * to ensure it's part of the reactive tree and updates correctly during client-side navigation.\n * The component uses portals internally to render content into the `<head>` element.\n *\n * Development version: filters out dev styles link after hydration and\n * includes a fallback cleanup effect for hydration mismatch cases.\n */\nexport function HeadContent() {\n const tags = useTags()\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 createEffect(() => {\n if (hydrated()) {\n document\n .querySelectorAll(`link[${DEV_STYLES_ATTR}]`)\n .forEach((el) => el.remove())\n }\n })\n\n // Filter out dev styles after hydration\n const filteredTags = createMemo(() => {\n if (hydrated()) {\n return tags().filter((tag) => !tag.attrs?.[DEV_STYLES_ATTR])\n }\n return tags()\n })\n\n return (\n <MetaProvider>\n <For each={filteredTags()}>{(tag) => <Asset {...tag} />}</For>\n </MetaProvider>\n )\n}\n"],"names":["DEV_STYLES_ATTR","HeadContent","tags","useTags","hydrated","useHydrated","createEffect","document","querySelectorAll","forEach","el","remove","filteredTags","createMemo","filter","tag","attrs","_$createComponent","MetaProvider","children","For","each","Asset"],"mappings":";;;;;;;;AAMA,MAAMA,kBAAkB;AAWjB,SAASC,cAAc;AAC5B,QAAMC,OAAOC,iBAAAA,QAAAA;AACb,QAAMC,WAAWC,WAAAA,YAAAA;AAIjBC,QAAAA,aAAa,MAAM;AACjB,QAAIF,YAAY;AACdG,eACGC,iBAAiB,QAAQR,eAAe,GAAG,EAC3CS,QAASC,CAAAA,OAAOA,GAAGC,OAAAA,CAAQ;AAAA,IAChC;AAAA,EACF,CAAC;AAGD,QAAMC,eAAeC,MAAAA,WAAW,MAAM;AACpC,QAAIT,YAAY;AACd,aAAOF,KAAAA,EAAOY,OAAQC,CAAAA,QAAQ,CAACA,IAAIC,QAAQhB,eAAe,CAAC;AAAA,IAC7D;AACA,WAAOE,KAAAA;AAAAA,EACT,CAAC;AAED,SAAAe,QAAAA,gBACGC,KAAAA,cAAY;AAAA,IAAA,IAAAC,WAAA;AAAA,aAAAF,QAAAA,gBACVG,MAAAA,KAAG;AAAA,QAAA,IAACC,OAAI;AAAA,iBAAET,aAAAA;AAAAA,QAAc;AAAA,QAAAO,UAAIJ,CAAAA,QAAGE,QAAAA,gBAAMK,MAAAA,OAAUP,GAAG;AAAA,MAAA,CAAI;AAAA,IAAA;AAAA,EAAA,CAAA;AAG7D;;"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @description The `HeadContent` component is used to render meta tags, links, and scripts for the current route.
|
|
3
|
+
* When using full document hydration (hydrating from `<html>`), this component should be rendered in the `<body>`
|
|
4
|
+
* to ensure it's part of the reactive tree and updates correctly during client-side navigation.
|
|
5
|
+
* The component uses portals internally to render content into the `<head>` element.
|
|
6
|
+
*
|
|
7
|
+
* Development version: filters out dev styles link after hydration and
|
|
8
|
+
* includes a fallback cleanup effect for hydration mismatch cases.
|
|
9
|
+
*/
|
|
10
|
+
export declare function HeadContent(): import("solid-js").JSX.Element;
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
|
+
const Solid = require("solid-js");
|
|
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 Solid__namespace = /* @__PURE__ */ _interopNamespaceDefault(Solid);
|
|
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 = Solid__namespace.createMemo(() => {
|
|
33
|
+
const resultMeta = [];
|
|
34
|
+
const metaByAttribute = {};
|
|
35
|
+
let title;
|
|
36
|
+
const routeMetasArray = routeMeta();
|
|
37
|
+
for (let i = routeMetasArray.length - 1; i >= 0; i--) {
|
|
38
|
+
const metas = routeMetasArray[i];
|
|
39
|
+
for (let j = metas.length - 1; j >= 0; j--) {
|
|
40
|
+
const m = metas[j];
|
|
41
|
+
if (!m) continue;
|
|
42
|
+
if (m.title) {
|
|
43
|
+
if (!title) {
|
|
44
|
+
title = {
|
|
45
|
+
tag: "title",
|
|
46
|
+
children: m.title
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
} else if ("script:ld+json" in m) {
|
|
50
|
+
try {
|
|
51
|
+
const json = JSON.stringify(m["script:ld+json"]);
|
|
52
|
+
resultMeta.push({
|
|
53
|
+
tag: "script",
|
|
54
|
+
attrs: {
|
|
55
|
+
type: "application/ld+json"
|
|
56
|
+
},
|
|
57
|
+
children: routerCore.escapeHtml(json)
|
|
58
|
+
});
|
|
59
|
+
} catch {
|
|
60
|
+
}
|
|
61
|
+
} else {
|
|
62
|
+
const attribute = m.name ?? m.property;
|
|
63
|
+
if (attribute) {
|
|
64
|
+
if (metaByAttribute[attribute]) {
|
|
65
|
+
continue;
|
|
66
|
+
} else {
|
|
67
|
+
metaByAttribute[attribute] = true;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
resultMeta.push({
|
|
71
|
+
tag: "meta",
|
|
72
|
+
attrs: {
|
|
73
|
+
...m,
|
|
74
|
+
nonce
|
|
75
|
+
}
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
if (title) {
|
|
81
|
+
resultMeta.push(title);
|
|
82
|
+
}
|
|
83
|
+
if (router.options.ssr?.nonce) {
|
|
84
|
+
resultMeta.push({
|
|
85
|
+
tag: "meta",
|
|
86
|
+
attrs: {
|
|
87
|
+
property: "csp-nonce",
|
|
88
|
+
content: router.options.ssr.nonce
|
|
89
|
+
}
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
resultMeta.reverse();
|
|
93
|
+
return resultMeta;
|
|
94
|
+
});
|
|
95
|
+
const links = useRouterState.useRouterState({
|
|
96
|
+
select: (state) => {
|
|
97
|
+
const constructed = state.matches.map((match) => match.links).filter(Boolean).flat(1).map((link) => ({
|
|
98
|
+
tag: "link",
|
|
99
|
+
attrs: {
|
|
100
|
+
...link,
|
|
101
|
+
nonce
|
|
102
|
+
}
|
|
103
|
+
}));
|
|
104
|
+
const manifest = router.ssr?.manifest;
|
|
105
|
+
const assets = state.matches.map((match) => manifest?.routes[match.routeId]?.assets ?? []).filter(Boolean).flat(1).filter((asset) => asset.tag === "link").map((asset) => ({
|
|
106
|
+
tag: "link",
|
|
107
|
+
attrs: {
|
|
108
|
+
...asset.attrs,
|
|
109
|
+
nonce
|
|
110
|
+
}
|
|
111
|
+
}));
|
|
112
|
+
return [...constructed, ...assets];
|
|
113
|
+
}
|
|
114
|
+
});
|
|
115
|
+
const preloadLinks = useRouterState.useRouterState({
|
|
116
|
+
select: (state) => {
|
|
117
|
+
const preloadLinks2 = [];
|
|
118
|
+
state.matches.map((match) => router.looseRoutesById[match.routeId]).forEach((route) => router.ssr?.manifest?.routes[route.id]?.preloads?.filter(Boolean).forEach((preload) => {
|
|
119
|
+
preloadLinks2.push({
|
|
120
|
+
tag: "link",
|
|
121
|
+
attrs: {
|
|
122
|
+
rel: "modulepreload",
|
|
123
|
+
href: preload,
|
|
124
|
+
nonce
|
|
125
|
+
}
|
|
126
|
+
});
|
|
127
|
+
}));
|
|
128
|
+
return preloadLinks2;
|
|
129
|
+
}
|
|
130
|
+
});
|
|
131
|
+
const styles = useRouterState.useRouterState({
|
|
132
|
+
select: (state) => state.matches.map((match) => match.styles).flat(1).filter(Boolean).map(({
|
|
133
|
+
children,
|
|
134
|
+
...style
|
|
135
|
+
}) => ({
|
|
136
|
+
tag: "style",
|
|
137
|
+
attrs: {
|
|
138
|
+
...style,
|
|
139
|
+
nonce
|
|
140
|
+
},
|
|
141
|
+
children
|
|
142
|
+
}))
|
|
143
|
+
});
|
|
144
|
+
const headScripts = useRouterState.useRouterState({
|
|
145
|
+
select: (state) => state.matches.map((match) => match.headScripts).flat(1).filter(Boolean).map(({
|
|
146
|
+
children,
|
|
147
|
+
...script
|
|
148
|
+
}) => ({
|
|
149
|
+
tag: "script",
|
|
150
|
+
attrs: {
|
|
151
|
+
...script,
|
|
152
|
+
nonce
|
|
153
|
+
},
|
|
154
|
+
children
|
|
155
|
+
}))
|
|
156
|
+
});
|
|
157
|
+
return () => uniqBy([...meta(), ...preloadLinks(), ...links(), ...styles(), ...headScripts()], (d) => {
|
|
158
|
+
return JSON.stringify(d);
|
|
159
|
+
});
|
|
160
|
+
};
|
|
161
|
+
function uniqBy(arr, fn) {
|
|
162
|
+
const seen = /* @__PURE__ */ new Set();
|
|
163
|
+
return arr.filter((item) => {
|
|
164
|
+
const key = fn(item);
|
|
165
|
+
if (seen.has(key)) {
|
|
166
|
+
return false;
|
|
167
|
+
}
|
|
168
|
+
seen.add(key);
|
|
169
|
+
return true;
|
|
170
|
+
});
|
|
171
|
+
}
|
|
172
|
+
exports.uniqBy = uniqBy;
|
|
173
|
+
exports.useTags = useTags;
|
|
174
|
+
//# sourceMappingURL=headContentUtils.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"headContentUtils.cjs","sources":["../../src/headContentUtils.tsx"],"sourcesContent":["import * as Solid from 'solid-js'\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: Solid.Accessor<Array<RouterManagedTag>> = Solid.createMemo(() => {\n const resultMeta: Array<RouterManagedTag> = []\n const metaByAttribute: Record<string, true> = {}\n let title: RouterManagedTag | undefined\n const routeMetasArray = routeMeta()\n for (let i = routeMetasArray.length - 1; i >= 0; i--) {\n const metas = routeMetasArray[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 innerHTML\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 (router.options.ssr?.nonce) {\n resultMeta.push({\n tag: 'meta',\n attrs: {\n property: 'csp-nonce',\n content: router.options.ssr.nonce,\n },\n })\n }\n resultMeta.reverse()\n\n return resultMeta\n })\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 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: { ...asset.attrs, nonce },\n }) satisfies RouterManagedTag,\n )\n\n return [...constructed, ...assets]\n },\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 })\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, ...style }) => ({\n tag: 'style',\n attrs: {\n ...style,\n nonce,\n },\n children,\n })),\n })\n\n const headScripts = 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 })\n\n return () =>\n 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":["useTags","router","useRouter","nonce","options","ssr","routeMeta","useRouterState","select","state","matches","map","match","meta","filter","Boolean","Solid","createMemo","resultMeta","metaByAttribute","title","routeMetasArray","i","length","metas","j","m","tag","children","json","JSON","stringify","push","attrs","type","escapeHtml","attribute","name","property","content","reverse","links","constructed","flat","link","manifest","assets","routes","routeId","asset","preloadLinks","looseRoutesById","forEach","route","id","preloads","preload","rel","href","styles","style","headScripts","script","uniqBy","d","arr","fn","seen","Set","item","key","has","add"],"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,
|
|
@@ -253,6 +254,6 @@ exports.DefaultGlobalNotFound = notFound.DefaultGlobalNotFound;
|
|
|
253
254
|
exports.ScriptOnce = ScriptOnce.ScriptOnce;
|
|
254
255
|
exports.Asset = Asset.Asset;
|
|
255
256
|
exports.HeadContent = HeadContent.HeadContent;
|
|
256
|
-
exports.useTags =
|
|
257
|
+
exports.useTags = headContentUtils.useTags;
|
|
257
258
|
exports.Scripts = Scripts.Scripts;
|
|
258
259
|
//# 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
|
@@ -45,7 +45,8 @@ export type { ValidateLinkOptions, ValidateUseSearchOptions, ValidateUseParamsOp
|
|
|
45
45
|
export type { ValidateFromPath, ValidateToPath, ValidateSearch, ValidateParams, InferFrom, InferTo, InferMaskTo, InferMaskFrom, ValidateNavigateOptions, ValidateNavigateOptionsArray, ValidateRedirectOptions, ValidateRedirectOptionsArray, ValidateId, InferStrict, InferShouldThrow, InferSelected, ValidateUseSearchResult, ValidateUseParamsResult, } from '@tanstack/router-core';
|
|
46
46
|
export { ScriptOnce } from './ScriptOnce.cjs';
|
|
47
47
|
export { Asset } from './Asset.cjs';
|
|
48
|
-
export { HeadContent
|
|
48
|
+
export { HeadContent } from './HeadContent.cjs';
|
|
49
|
+
export { useTags } from './headContentUtils.cjs';
|
|
49
50
|
export { Scripts } from './Scripts.cjs';
|
|
50
51
|
export { composeRewrites } from '@tanstack/router-core';
|
|
51
52
|
export type { LocationRewrite, LocationRewriteFunction, } from '@tanstack/router-core';
|