@tanstack/vue-router 1.170.6 → 1.170.8
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/esm/HeadContent.d.ts +2 -2
- package/dist/esm/HeadContent.dev.js +2 -2
- package/dist/esm/HeadContent.dev.js.map +1 -1
- package/dist/esm/HeadContent.js +84 -4
- package/dist/esm/HeadContent.js.map +1 -1
- package/dist/esm/Scripts.js +60 -49
- package/dist/esm/Scripts.js.map +1 -1
- package/dist/esm/headContentUtils.d.ts +0 -1
- package/dist/esm/headContentUtils.js +34 -44
- package/dist/esm/headContentUtils.js.map +1 -1
- package/dist/source/HeadContent.d.ts +2 -2
- package/dist/source/HeadContent.dev.jsx +2 -2
- package/dist/source/HeadContent.dev.jsx.map +1 -1
- package/dist/source/HeadContent.jsx +117 -4
- package/dist/source/HeadContent.jsx.map +1 -1
- package/dist/source/Scripts.jsx +72 -70
- package/dist/source/Scripts.jsx.map +1 -1
- package/dist/source/headContentUtils.d.ts +0 -1
- package/dist/source/headContentUtils.jsx +43 -66
- package/dist/source/headContentUtils.jsx.map +1 -1
- package/package.json +2 -2
- package/src/HeadContent.dev.tsx +5 -3
- package/src/HeadContent.tsx +150 -6
- package/src/Scripts.tsx +102 -80
- package/src/headContentUtils.tsx +53 -79
|
@@ -12,9 +12,9 @@ export declare const HeadContent: Vue.DefineComponent<Vue.ExtractPropTypes<{
|
|
|
12
12
|
type: Vue.PropType<AssetCrossOriginConfig>;
|
|
13
13
|
default: undefined;
|
|
14
14
|
};
|
|
15
|
-
}>, () => Vue.VNode<Vue.RendererNode, Vue.RendererElement, {
|
|
15
|
+
}>, () => (Vue.VNode<Vue.RendererNode, Vue.RendererElement, {
|
|
16
16
|
[key: string]: any;
|
|
17
|
-
}>[], {}, {}, {}, Vue.ComponentOptionsMixin, Vue.ComponentOptionsMixin, {}, string, Vue.PublicProps, Readonly<Vue.ExtractPropTypes<{
|
|
17
|
+
}> | null)[], {}, {}, {}, Vue.ComponentOptionsMixin, Vue.ComponentOptionsMixin, {}, string, Vue.PublicProps, Readonly<Vue.ExtractPropTypes<{
|
|
18
18
|
assetCrossOrigin: {
|
|
19
19
|
type: Vue.PropType<AssetCrossOriginConfig>;
|
|
20
20
|
default: undefined;
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { useHydrated } from "./ClientOnly.js";
|
|
2
2
|
import { Asset } from "./Asset.js";
|
|
3
3
|
import { useTags } from "./headContentUtils.js";
|
|
4
|
+
import { DEV_STYLES_ATTR } from "@tanstack/router-core";
|
|
4
5
|
import * as Vue from "vue";
|
|
5
6
|
//#region src/HeadContent.dev.tsx
|
|
6
|
-
var DEV_STYLES_ATTR = "data-tanstack-router-dev-styles";
|
|
7
7
|
/**
|
|
8
8
|
* @description The `HeadContent` component is used to render meta tags, links, and scripts for the current route.
|
|
9
9
|
* It should be rendered in the `<head>` of your document.
|
|
@@ -23,7 +23,7 @@ var HeadContent = Vue.defineComponent({
|
|
|
23
23
|
document.querySelectorAll(`link[${DEV_STYLES_ATTR}]`).forEach((el) => el.remove());
|
|
24
24
|
});
|
|
25
25
|
return () => {
|
|
26
|
-
return (hydrated.value ? tags().filter((tag) =>
|
|
26
|
+
return (hydrated.value ? tags().filter((tag) => tag.tag !== "link" || tag.attrs?.[DEV_STYLES_ATTR] !== true) : tags()).map((tag) => Vue.h(Asset, {
|
|
27
27
|
...tag,
|
|
28
28
|
key: `tsr-meta-${JSON.stringify(tag)}`
|
|
29
29
|
}));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"HeadContent.dev.js","names":["Vue","Asset","useHydrated","useTags","
|
|
1
|
+
{"version":3,"file":"HeadContent.dev.js","names":["Vue","DEV_STYLES_ATTR","Asset","useHydrated","useTags","HeadContent","defineComponent","name","props","assetCrossOrigin","type","String","Object","default","undefined","setup","tags","hydrated","onMounted","document","querySelectorAll","forEach","el","remove","filteredTags","value","filter","tag","attrs","map","h","key","JSON","stringify"],"sources":["../../src/HeadContent.dev.tsx"],"sourcesContent":["import * as Vue from 'vue'\nimport { DEV_STYLES_ATTR } from '@tanstack/router-core'\n\nimport { Asset } from './Asset'\nimport { useHydrated } from './ClientOnly'\nimport { useTags } from './headContentUtils'\nimport type { AssetCrossOriginConfig } from '@tanstack/router-core'\n\n/**\n * @description The `HeadContent` component is used to render meta tags, links, and scripts for the current route.\n * It should be rendered in the `<head>` of your document.\n *\n * This is the development version that filters out dev styles after hydration.\n */\nexport const HeadContent = Vue.defineComponent({\n name: 'HeadContent',\n props: {\n assetCrossOrigin: {\n type: [String, Object] as Vue.PropType<AssetCrossOriginConfig>,\n default: undefined,\n },\n },\n setup(props) {\n const tags = useTags(props.assetCrossOrigin)\n const hydrated = useHydrated()\n\n // Fallback cleanup for hydration mismatch cases\n Vue.onMounted(() => {\n document\n .querySelectorAll(`link[${DEV_STYLES_ATTR}]`)\n .forEach((el) => el.remove())\n })\n\n return () => {\n // Filter out dev styles after hydration\n const filteredTags = hydrated.value\n ? tags().filter(\n (tag) =>\n tag.tag !== 'link' || tag.attrs?.[DEV_STYLES_ATTR] !== true,\n )\n : tags()\n\n return filteredTags.map((tag) =>\n Vue.h(Asset, {\n ...tag,\n key: `tsr-meta-${JSON.stringify(tag)}`,\n }),\n )\n }\n },\n})\n"],"mappings":";;;;;;;;;;;;AAcA,IAAaK,cAAcL,IAAIM,gBAAgB;CAC7CC,MAAM;CACNC,OAAO,EACLC,kBAAkB;EAChBC,MAAM,CAACC,QAAQC,OAA+C;EAC9DC,SAASC,KAAAA;EACX,EACD;CACDC,MAAMP,OAAO;EACX,MAAMQ,OAAOZ,QAAQI,MAAMC,iBAAiB;EAC5C,MAAMQ,WAAWd,aAAa;AAG9BH,MAAIkB,gBAAgB;AAClBC,YACGC,iBAAiB,QAAQnB,gBAAe,GAAI,CAC5CoB,SAASC,OAAOA,GAAGC,QAAQ,CAAC;IAC/B;AAEF,eAAa;AASX,WAPqBN,SAASQ,QAC1BT,MAAM,CAACU,QACJC,QACCA,IAAIA,QAAQ,UAAUA,IAAIC,QAAQ3B,qBAAqB,KAC1D,GACDe,MAAM,EAEUa,KAAKF,QACvB3B,IAAI8B,EAAE5B,OAAO;IACX,GAAGyB;IACHI,KAAK,YAAYC,KAAKC,UAAUN,IAAI;IACrC,CACH,CAAC;;;CAGN,CAAC"}
|
package/dist/esm/HeadContent.js
CHANGED
|
@@ -1,7 +1,56 @@
|
|
|
1
|
+
import { useRouter } from "./useRouter.js";
|
|
1
2
|
import { Asset } from "./Asset.js";
|
|
2
3
|
import { useTags } from "./headContentUtils.js";
|
|
3
4
|
import * as Vue from "vue";
|
|
5
|
+
import { isServer } from "@tanstack/router-core/isServer";
|
|
4
6
|
//#region src/HeadContent.tsx
|
|
7
|
+
function attrsMatch(attrs, element) {
|
|
8
|
+
let expectedAttrCount = 0;
|
|
9
|
+
for (const name in attrs) {
|
|
10
|
+
const value = attrs[name];
|
|
11
|
+
if (value === void 0 || value === false || value === null) continue;
|
|
12
|
+
expectedAttrCount++;
|
|
13
|
+
const attrName = name.toLowerCase();
|
|
14
|
+
if (value === true) {
|
|
15
|
+
if (!element.hasAttribute(attrName)) return false;
|
|
16
|
+
continue;
|
|
17
|
+
}
|
|
18
|
+
if (element.getAttribute(attrName) !== String(value)) return false;
|
|
19
|
+
}
|
|
20
|
+
return expectedAttrCount === element.attributes.length;
|
|
21
|
+
}
|
|
22
|
+
function reconcileHydratedHead(tags, preservedHeadTagElements) {
|
|
23
|
+
if (typeof document === "undefined") return;
|
|
24
|
+
const matchedHeadElements = /* @__PURE__ */ new Set();
|
|
25
|
+
const hydratedLinks = document.head.querySelectorAll("link");
|
|
26
|
+
for (const tag of tags) {
|
|
27
|
+
if (tag.tag !== "link") continue;
|
|
28
|
+
const attrs = tag.attrs;
|
|
29
|
+
const rel = typeof attrs?.rel === "string" ? attrs.rel.toLowerCase() : void 0;
|
|
30
|
+
if (rel !== "stylesheet" && rel !== "preload" && rel !== "modulepreload") continue;
|
|
31
|
+
for (const element of hydratedLinks) if (!matchedHeadElements.has(element) && attrsMatch(attrs, element)) {
|
|
32
|
+
matchedHeadElements.add(element);
|
|
33
|
+
const key = JSON.stringify(tag);
|
|
34
|
+
(preservedHeadTagElements[key] ||= []).push(element);
|
|
35
|
+
break;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
function cleanupInactivePreservedHeadElements(preservedHeadTagElements, activeElements) {
|
|
40
|
+
for (const key in preservedHeadTagElements) {
|
|
41
|
+
const elements = preservedHeadTagElements[key];
|
|
42
|
+
let nextElements;
|
|
43
|
+
for (const element of elements) if (activeElements.has(element)) (nextElements ||= []).push(element);
|
|
44
|
+
else if (!shouldRemoveInactivePreservedHeadElement(element)) (nextElements ||= []).push(element);
|
|
45
|
+
else element.remove();
|
|
46
|
+
if (nextElements) preservedHeadTagElements[key] = nextElements;
|
|
47
|
+
else delete preservedHeadTagElements[key];
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
function shouldRemoveInactivePreservedHeadElement(element) {
|
|
51
|
+
const rel = element.getAttribute("rel")?.toLowerCase();
|
|
52
|
+
return rel === "preload" || rel === "modulepreload";
|
|
53
|
+
}
|
|
5
54
|
/**
|
|
6
55
|
* @description The `HeadContent` component is used to render meta tags, links, and scripts for the current route.
|
|
7
56
|
* It should be rendered in the `<head>` of your document.
|
|
@@ -13,12 +62,43 @@ var HeadContent = Vue.defineComponent({
|
|
|
13
62
|
default: void 0
|
|
14
63
|
} },
|
|
15
64
|
setup(props) {
|
|
65
|
+
const router = useRouter();
|
|
16
66
|
const tags = useTags(props.assetCrossOrigin);
|
|
67
|
+
if (isServer ?? router.isServer) return () => {
|
|
68
|
+
return tags().map((tag) => {
|
|
69
|
+
const key = JSON.stringify(tag);
|
|
70
|
+
return Vue.h(Asset, {
|
|
71
|
+
...tag,
|
|
72
|
+
key: `tsr-meta-${key}`
|
|
73
|
+
});
|
|
74
|
+
});
|
|
75
|
+
};
|
|
76
|
+
const preservedHeadTagElements = {};
|
|
77
|
+
let activePreservedHeadElements = /* @__PURE__ */ new Set();
|
|
78
|
+
if (router.ssr) reconcileHydratedHead(tags(), preservedHeadTagElements);
|
|
79
|
+
Vue.onUpdated(() => {
|
|
80
|
+
cleanupInactivePreservedHeadElements(preservedHeadTagElements, activePreservedHeadElements);
|
|
81
|
+
});
|
|
82
|
+
Vue.onUnmounted(() => {
|
|
83
|
+
cleanupInactivePreservedHeadElements(preservedHeadTagElements, /* @__PURE__ */ new Set());
|
|
84
|
+
});
|
|
17
85
|
return () => {
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
86
|
+
const renderedPreservedHeadTagKeys = {};
|
|
87
|
+
activePreservedHeadElements = /* @__PURE__ */ new Set();
|
|
88
|
+
return tags().map((tag) => {
|
|
89
|
+
const key = JSON.stringify(tag);
|
|
90
|
+
const renderedCount = renderedPreservedHeadTagKeys[key] || 0;
|
|
91
|
+
const preservedElement = preservedHeadTagElements[key]?.[renderedCount];
|
|
92
|
+
if (preservedElement?.isConnected) {
|
|
93
|
+
renderedPreservedHeadTagKeys[key] = renderedCount + 1;
|
|
94
|
+
activePreservedHeadElements.add(preservedElement);
|
|
95
|
+
return null;
|
|
96
|
+
}
|
|
97
|
+
return Vue.h(Asset, {
|
|
98
|
+
...tag,
|
|
99
|
+
key: `tsr-meta-${key}`
|
|
100
|
+
});
|
|
101
|
+
});
|
|
22
102
|
};
|
|
23
103
|
}
|
|
24
104
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"HeadContent.js","names":["Vue","Asset","useTags","
|
|
1
|
+
{"version":3,"file":"HeadContent.js","names":["Vue","isServer","Asset","useTags","useRouter","attrsMatch","attrs","element","expectedAttrCount","name","value","undefined","attrName","toLowerCase","hasAttribute","getAttribute","String","attributes","length","reconcileHydratedHead","tags","preservedHeadTagElements","document","matchedHeadElements","Set","hydratedLinks","head","querySelectorAll","tag","rel","has","add","key","JSON","stringify","push","cleanupInactivePreservedHeadElements","activeElements","elements","nextElements","shouldRemoveInactivePreservedHeadElement","remove","HeadContent","defineComponent","props","assetCrossOrigin","type","Object","default","setup","router","map","h","activePreservedHeadElements","ssr","onUpdated","onUnmounted","renderedPreservedHeadTagKeys","renderedTags","renderedCount","preservedElement","isConnected"],"sources":["../../src/HeadContent.tsx"],"sourcesContent":["import * as Vue from 'vue'\nimport { isServer } from '@tanstack/router-core/isServer'\n\nimport { Asset } from './Asset'\nimport { useTags } from './headContentUtils'\nimport { useRouter } from './useRouter'\nimport type {\n AssetCrossOriginConfig,\n RouterManagedTag,\n} from '@tanstack/router-core'\n\nfunction attrsMatch(attrs: Record<string, any>, element: Element) {\n let expectedAttrCount = 0\n\n for (const name in attrs) {\n const value = attrs[name]\n if (value === undefined || value === false || value === null) {\n continue\n }\n\n expectedAttrCount++\n const attrName = name.toLowerCase()\n\n if (value === true) {\n if (!element.hasAttribute(attrName)) {\n return false\n }\n\n continue\n }\n\n if (element.getAttribute(attrName) !== String(value)) {\n return false\n }\n }\n\n return expectedAttrCount === element.attributes.length\n}\n\nfunction reconcileHydratedHead(\n tags: Array<RouterManagedTag>,\n preservedHeadTagElements: Record<string, Array<Element>>,\n) {\n if (typeof document === 'undefined') {\n return\n }\n\n const matchedHeadElements = new Set<Element>()\n const hydratedLinks = document.head.querySelectorAll('link')\n\n for (const tag of tags) {\n if (tag.tag !== 'link') {\n continue\n }\n\n const attrs = tag.attrs\n const rel =\n typeof attrs?.rel === 'string' ? attrs.rel.toLowerCase() : undefined\n if (rel !== 'stylesheet' && rel !== 'preload' && rel !== 'modulepreload') {\n continue\n }\n\n for (const element of hydratedLinks) {\n if (!matchedHeadElements.has(element) && attrsMatch(attrs!, element)) {\n matchedHeadElements.add(element)\n const key = JSON.stringify(tag)\n ;(preservedHeadTagElements[key] ||= []).push(element)\n break\n }\n }\n }\n}\n\nfunction cleanupInactivePreservedHeadElements(\n preservedHeadTagElements: Record<string, Array<Element>>,\n activeElements: Set<Element>,\n) {\n for (const key in preservedHeadTagElements) {\n const elements = preservedHeadTagElements[key]!\n let nextElements: Array<Element> | undefined\n\n for (const element of elements) {\n if (activeElements.has(element)) {\n ;(nextElements ||= []).push(element)\n } else if (!shouldRemoveInactivePreservedHeadElement(element)) {\n ;(nextElements ||= []).push(element)\n } else {\n element.remove()\n }\n }\n\n if (nextElements) {\n preservedHeadTagElements[key] = nextElements\n } else {\n delete preservedHeadTagElements[key]\n }\n }\n}\n\nfunction shouldRemoveInactivePreservedHeadElement(element: Element) {\n const rel = element.getAttribute('rel')?.toLowerCase()\n return rel === 'preload' || rel === 'modulepreload'\n}\n\nexport interface HeadContentProps {\n assetCrossOrigin?: AssetCrossOriginConfig\n}\n\n/**\n * @description The `HeadContent` component is used to render meta tags, links, and scripts for the current route.\n * It should be rendered in the `<head>` of your document.\n */\nexport const HeadContent = Vue.defineComponent({\n name: 'HeadContent',\n props: {\n assetCrossOrigin: {\n type: [String, Object] as Vue.PropType<AssetCrossOriginConfig>,\n default: undefined,\n },\n },\n setup(props) {\n const router = useRouter()\n const tags = useTags(props.assetCrossOrigin)\n\n if (isServer ?? router.isServer) {\n return () => {\n return tags().map((tag) => {\n const key = JSON.stringify(tag)\n return Vue.h(Asset, {\n ...tag,\n key: `tsr-meta-${key}`,\n })\n })\n }\n }\n\n const preservedHeadTagElements: Record<string, Array<Element>> = {}\n let activePreservedHeadElements = new Set<Element>()\n\n if (router.ssr) {\n reconcileHydratedHead(tags(), preservedHeadTagElements)\n }\n\n Vue.onUpdated(() => {\n cleanupInactivePreservedHeadElements(\n preservedHeadTagElements,\n activePreservedHeadElements,\n )\n })\n Vue.onUnmounted(() => {\n cleanupInactivePreservedHeadElements(\n preservedHeadTagElements,\n new Set<Element>(),\n )\n })\n\n return () => {\n const renderedPreservedHeadTagKeys: Record<string, number> = {}\n activePreservedHeadElements = new Set<Element>()\n const renderedTags = tags().map((tag) => {\n const key = JSON.stringify(tag)\n const renderedCount = renderedPreservedHeadTagKeys[key] || 0\n const preservedElement = preservedHeadTagElements[key]?.[renderedCount]\n if (preservedElement?.isConnected) {\n renderedPreservedHeadTagKeys[key] = renderedCount + 1\n activePreservedHeadElements.add(preservedElement)\n return null\n }\n\n return Vue.h(Asset, {\n ...tag,\n key: `tsr-meta-${key}`,\n })\n })\n\n return renderedTags\n }\n },\n})\n"],"mappings":"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"}
|
package/dist/esm/Scripts.js
CHANGED
|
@@ -2,6 +2,7 @@ import { useRouter } from "./useRouter.js";
|
|
|
2
2
|
import { Asset } from "./Asset.js";
|
|
3
3
|
import * as Vue from "vue";
|
|
4
4
|
import { Fragment, createVNode, mergeProps } from "vue";
|
|
5
|
+
import { isServer } from "@tanstack/router-core/isServer";
|
|
5
6
|
import { useStore } from "@tanstack/vue-store";
|
|
6
7
|
//#region src/Scripts.tsx
|
|
7
8
|
var Scripts = Vue.defineComponent({
|
|
@@ -10,72 +11,82 @@ var Scripts = Vue.defineComponent({
|
|
|
10
11
|
const router = useRouter();
|
|
11
12
|
const nonce = router.options.ssr?.nonce;
|
|
12
13
|
const matches = useStore(router.stores.matches, (value) => value);
|
|
13
|
-
const
|
|
14
|
+
const getAssetScripts = (matches) => {
|
|
14
15
|
const assetScripts = [];
|
|
15
16
|
const manifest = router.ssr?.manifest;
|
|
16
17
|
if (!manifest) return [];
|
|
17
|
-
matches.
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
18
|
+
matches.forEach((match) => {
|
|
19
|
+
manifest.routes[match.routeId]?.scripts?.forEach((asset) => {
|
|
20
|
+
assetScripts.push({
|
|
21
|
+
tag: "script",
|
|
22
|
+
attrs: {
|
|
23
|
+
...asset.attrs,
|
|
24
|
+
nonce
|
|
25
|
+
},
|
|
26
|
+
children: asset.children
|
|
27
|
+
});
|
|
25
28
|
});
|
|
26
|
-
})
|
|
29
|
+
});
|
|
27
30
|
return assetScripts;
|
|
28
|
-
}
|
|
29
|
-
const
|
|
31
|
+
};
|
|
32
|
+
const getScripts = (matches) => matches.map((match) => match.scripts).flat(1).filter(Boolean).map(({ children, ...script }) => ({
|
|
30
33
|
tag: "script",
|
|
31
34
|
attrs: {
|
|
32
35
|
...script,
|
|
33
36
|
nonce
|
|
34
37
|
},
|
|
35
38
|
children
|
|
36
|
-
}))
|
|
39
|
+
}));
|
|
40
|
+
const assetScripts = Vue.computed(() => getAssetScripts(matches.value));
|
|
41
|
+
const scripts = Vue.computed(() => getScripts(matches.value));
|
|
37
42
|
const mounted = Vue.ref(false);
|
|
38
43
|
Vue.onMounted(() => {
|
|
39
44
|
mounted.value = true;
|
|
40
45
|
});
|
|
41
|
-
return () => {
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
allScripts.push({
|
|
48
|
-
tag: "script",
|
|
49
|
-
attrs: {
|
|
50
|
-
nonce,
|
|
51
|
-
"data-allow-mismatch": true
|
|
52
|
-
},
|
|
53
|
-
children: ""
|
|
54
|
-
});
|
|
55
|
-
allScripts.push({
|
|
56
|
-
tag: "script",
|
|
57
|
-
attrs: {
|
|
58
|
-
nonce,
|
|
59
|
-
id: "$tsr-stream-barrier",
|
|
60
|
-
"data-allow-mismatch": true
|
|
61
|
-
},
|
|
62
|
-
children: ""
|
|
63
|
-
});
|
|
64
|
-
for (const asset of assetScripts.value) allScripts.push({
|
|
65
|
-
tag: "script",
|
|
66
|
-
attrs: {
|
|
67
|
-
...asset.attrs,
|
|
68
|
-
"data-allow-mismatch": true
|
|
69
|
-
},
|
|
70
|
-
children: ""
|
|
71
|
-
});
|
|
72
|
-
}
|
|
73
|
-
for (const script of scripts.value.scripts) allScripts.push(script);
|
|
74
|
-
if (mounted.value || router.serverSsr) for (const asset of assetScripts.value) allScripts.push(asset);
|
|
75
|
-
return createVNode(Fragment, null, [allScripts.map((asset, i) => createVNode(Asset, mergeProps(asset, { "key": `tsr-scripts-${asset.tag}-${i}` }), null))]);
|
|
76
|
-
};
|
|
46
|
+
return () => renderScripts(router, {
|
|
47
|
+
scripts: scripts.value,
|
|
48
|
+
assetScripts: assetScripts.value,
|
|
49
|
+
mounted: mounted.value,
|
|
50
|
+
nonce
|
|
51
|
+
});
|
|
77
52
|
}
|
|
78
53
|
});
|
|
54
|
+
function renderScripts(router, { scripts, assetScripts, mounted, nonce }) {
|
|
55
|
+
const allScripts = [];
|
|
56
|
+
if ((isServer ?? router.isServer) && router.serverSsr) {
|
|
57
|
+
const serverBufferedScript = router.serverSsr.takeBufferedScripts();
|
|
58
|
+
if (serverBufferedScript) allScripts.push(serverBufferedScript);
|
|
59
|
+
} else if (router.ssr && !mounted) {
|
|
60
|
+
allScripts.push({
|
|
61
|
+
tag: "script",
|
|
62
|
+
attrs: {
|
|
63
|
+
nonce,
|
|
64
|
+
"data-allow-mismatch": true
|
|
65
|
+
},
|
|
66
|
+
children: ""
|
|
67
|
+
});
|
|
68
|
+
allScripts.push({
|
|
69
|
+
tag: "script",
|
|
70
|
+
attrs: {
|
|
71
|
+
nonce,
|
|
72
|
+
id: "$tsr-stream-barrier",
|
|
73
|
+
"data-allow-mismatch": true
|
|
74
|
+
},
|
|
75
|
+
children: ""
|
|
76
|
+
});
|
|
77
|
+
for (const asset of assetScripts) allScripts.push({
|
|
78
|
+
tag: "script",
|
|
79
|
+
attrs: {
|
|
80
|
+
...asset.attrs,
|
|
81
|
+
"data-allow-mismatch": true
|
|
82
|
+
},
|
|
83
|
+
children: ""
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
allScripts.push(...scripts);
|
|
87
|
+
if (mounted || (isServer ?? router.isServer) && router.serverSsr) allScripts.push(...assetScripts);
|
|
88
|
+
return createVNode(Fragment, null, [allScripts.map((asset, i) => createVNode(Asset, mergeProps(asset, { "key": `tsr-scripts-${asset.tag}-${i}` }), null))]);
|
|
89
|
+
}
|
|
79
90
|
//#endregion
|
|
80
91
|
export { Scripts };
|
|
81
92
|
|
package/dist/esm/Scripts.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Scripts.js","names":["Vue","useStore","Asset","useRouter","Scripts","defineComponent","name","setup","router","nonce","options","ssr","matches","stores","value","
|
|
1
|
+
{"version":3,"file":"Scripts.js","names":["Vue","useStore","isServer","Asset","useRouter","Scripts","defineComponent","name","setup","router","nonce","options","ssr","matches","stores","value","getAssetScripts","assetScripts","manifest","forEach","match","routeManifest","routes","routeId","scripts","asset","push","tag","attrs","children","getScripts","map","flat","filter","Boolean","script","computed","mounted","ref","onMounted","renderScripts","allScripts","serverSsr","serverBufferedScript","takeBufferedScripts","id","_createVNode","_Fragment","i","_mergeProps"],"sources":["../../src/Scripts.tsx"],"sourcesContent":["import * as Vue from 'vue'\nimport { useStore } from '@tanstack/vue-store'\nimport { isServer } from '@tanstack/router-core/isServer'\nimport { Asset } from './Asset'\nimport { useRouter } from './useRouter'\nimport type { RouterManagedTag } from '@tanstack/router-core'\n\ntype ScriptsRenderState = {\n scripts: Array<RouterManagedTag>\n assetScripts: Array<RouterManagedTag>\n mounted: boolean\n nonce?: string\n}\n\nexport const Scripts = Vue.defineComponent({\n name: 'Scripts',\n setup() {\n const router = useRouter()\n const nonce = router.options.ssr?.nonce\n const matches = useStore(router.stores.matches, (value) => value)\n\n const getAssetScripts = (matches: Array<any>) => {\n const assetScripts: Array<RouterManagedTag> = []\n const manifest = router.ssr?.manifest\n\n if (!manifest) {\n return []\n }\n\n matches.forEach((match) => {\n const routeManifest = manifest.routes[match.routeId]\n\n routeManifest?.scripts?.forEach((asset) => {\n assetScripts.push({\n tag: 'script',\n attrs: { ...asset.attrs, nonce },\n children: asset.children,\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 nonce,\n },\n children,\n }) satisfies RouterManagedTag,\n )\n\n const assetScripts = Vue.computed<Array<RouterManagedTag>>(() =>\n getAssetScripts(matches.value),\n )\n const scripts = Vue.computed<Array<RouterManagedTag>>(() =>\n getScripts(matches.value),\n )\n\n const mounted = Vue.ref(false)\n Vue.onMounted(() => {\n mounted.value = true\n })\n\n return () =>\n renderScripts(router, {\n scripts: scripts.value,\n assetScripts: assetScripts.value,\n mounted: mounted.value,\n nonce,\n })\n },\n})\n\nfunction renderScripts(\n router: ReturnType<typeof useRouter>,\n { scripts, assetScripts, mounted, nonce }: ScriptsRenderState,\n) {\n const allScripts: Array<RouterManagedTag> = []\n\n if ((isServer ?? router.isServer) && router.serverSsr) {\n const serverBufferedScript = router.serverSsr.takeBufferedScripts()\n if (serverBufferedScript) {\n allScripts.push(serverBufferedScript)\n }\n } else if (router.ssr && !mounted) {\n allScripts.push({\n tag: 'script',\n attrs: { nonce, 'data-allow-mismatch': true },\n children: '',\n } satisfies RouterManagedTag)\n\n allScripts.push({\n tag: 'script',\n attrs: {\n nonce,\n id: '$tsr-stream-barrier',\n 'data-allow-mismatch': true,\n },\n children: '',\n } satisfies RouterManagedTag)\n\n for (const asset of assetScripts) {\n allScripts.push({\n tag: 'script',\n attrs: {\n ...asset.attrs,\n 'data-allow-mismatch': true,\n },\n children: '',\n } satisfies RouterManagedTag)\n }\n }\n\n allScripts.push(...scripts)\n\n if (mounted || ((isServer ?? router.isServer) && router.serverSsr)) {\n allScripts.push(...assetScripts)\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":";;;;;;;AAcA,IAAaK,UAAUL,IAAIM,gBAAgB;CACzCC,MAAM;CACNC,QAAQ;EACN,MAAMC,SAASL,WAAW;EAC1B,MAAMM,QAAQD,OAAOE,QAAQC,KAAKF;EAClC,MAAMG,UAAUZ,SAASQ,OAAOK,OAAOD,UAAUE,UAAUA,MAAM;EAEjE,MAAMC,mBAAmBH,YAAwB;GAC/C,MAAMI,eAAwC,EAAE;GAChD,MAAMC,WAAWT,OAAOG,KAAKM;AAE7B,OAAI,CAACA,SACH,QAAO,EAAE;AAGXL,WAAQM,SAASC,UAAU;AACHF,aAASI,OAAOF,MAAMG,UAE7BC,SAASL,SAASM,UAAU;AACzCR,kBAAaS,KAAK;MAChBC,KAAK;MACLC,OAAO;OAAE,GAAGH,MAAMG;OAAOlB;OAAO;MAChCmB,UAAUJ,MAAMI;MACjB,CAAC;MACF;KACF;AAEF,UAAOZ;;EAGT,MAAMa,cAAcjB,YAEhBA,QACGkB,KAAKX,UAAUA,MAAMI,QAAS,CAC9BQ,KAAK,EAAE,CACPC,OAAOC,QAAQ,CAClBH,KACC,EAAEF,UAAU,GAAGM,cACb;GACCR,KAAK;GACLC,OAAO;IACL,GAAGO;IACHzB;IACD;GACDmB;GACD,EACJ;EAEH,MAAMZ,eAAejB,IAAIoC,eACvBpB,gBAAgBH,QAAQE,MAC1B,CAAC;EACD,MAAMS,UAAUxB,IAAIoC,eAClBN,WAAWjB,QAAQE,MACrB,CAAC;EAED,MAAMsB,UAAUrC,IAAIsC,IAAI,MAAM;AAC9BtC,MAAIuC,gBAAgB;AAClBF,WAAQtB,QAAQ;IAChB;AAEF,eACEyB,cAAc/B,QAAQ;GACpBe,SAASA,QAAQT;GACjBE,cAAcA,aAAaF;GAC3BsB,SAASA,QAAQtB;GACjBL;GACD,CAAC;;CAEP,CAAC;AAEF,SAAS8B,cACP/B,QACA,EAAEe,SAASP,cAAcoB,SAAS3B,SAClC;CACA,MAAM+B,aAAsC,EAAE;AAE9C,MAAKvC,YAAYO,OAAOP,aAAaO,OAAOiC,WAAW;EACrD,MAAMC,uBAAuBlC,OAAOiC,UAAUE,qBAAqB;AACnE,MAAID,qBACFF,YAAWf,KAAKiB,qBAAqB;YAE9BlC,OAAOG,OAAO,CAACyB,SAAS;AACjCI,aAAWf,KAAK;GACdC,KAAK;GACLC,OAAO;IAAElB;IAAO,uBAAuB;IAAM;GAC7CmB,UAAU;GACgB,CAAC;AAE7BY,aAAWf,KAAK;GACdC,KAAK;GACLC,OAAO;IACLlB;IACAmC,IAAI;IACJ,uBAAuB;IACxB;GACDhB,UAAU;GACgB,CAAC;AAE7B,OAAK,MAAMJ,SAASR,aAClBwB,YAAWf,KAAK;GACdC,KAAK;GACLC,OAAO;IACL,GAAGH,MAAMG;IACT,uBAAuB;IACxB;GACDC,UAAU;GACgB,CAAC;;AAIjCY,YAAWf,KAAK,GAAGF,QAAQ;AAE3B,KAAIa,YAAanC,YAAYO,OAAOP,aAAaO,OAAOiC,UACtDD,YAAWf,KAAK,GAAGT,aAAa;AAGlC,QAAA6B,YAAAC,UAAA,MAAA,CAEKN,WAAWV,KAAKN,OAAOuB,MAACF,YAAA3C,OAAA8C,WACZxB,OAAK,EAAA,OAAO,eAAeA,MAAME,IAAG,GAAIqB,KAAG,CAAA,EAAA,KACvD,CAAC,CAAA,CAAA"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { useRouter } from "./useRouter.js";
|
|
2
|
-
import { escapeHtml, getAssetCrossOrigin,
|
|
2
|
+
import { appendUniqueUserTags, escapeHtml, getAssetCrossOrigin, getScriptPreloadAttrs, resolveManifestCssLink } from "@tanstack/router-core";
|
|
3
3
|
import * as Vue from "vue";
|
|
4
4
|
import { useStore } from "@tanstack/vue-store";
|
|
5
5
|
//#region src/headContentUtils.tsx
|
|
@@ -47,17 +47,14 @@ var useTags = (assetCrossOrigin) => {
|
|
|
47
47
|
})));
|
|
48
48
|
const preloadMeta = Vue.computed(() => {
|
|
49
49
|
const preloadMeta = [];
|
|
50
|
-
matches.value.
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
href: preloadLink.href,
|
|
57
|
-
crossOrigin: getAssetCrossOrigin(assetCrossOrigin, "modulepreload") ?? preloadLink.crossOrigin
|
|
58
|
-
}
|
|
50
|
+
matches.value.forEach((match) => {
|
|
51
|
+
router.ssr?.manifest?.routes[match.routeId]?.preloads?.filter(Boolean).forEach((preload) => {
|
|
52
|
+
preloadMeta.push({
|
|
53
|
+
tag: "link",
|
|
54
|
+
attrs: { ...getScriptPreloadAttrs(router.ssr?.manifest, preload, assetCrossOrigin) }
|
|
55
|
+
});
|
|
59
56
|
});
|
|
60
|
-
})
|
|
57
|
+
});
|
|
61
58
|
return preloadMeta;
|
|
62
59
|
});
|
|
63
60
|
const headScripts = Vue.computed(() => matches.value.map((match) => match.headScripts).flat(1).filter(Boolean).map(({ children, ...script }) => ({
|
|
@@ -67,45 +64,38 @@ var useTags = (assetCrossOrigin) => {
|
|
|
67
64
|
})));
|
|
68
65
|
const manifestAssets = Vue.computed(() => {
|
|
69
66
|
const manifest = router.ssr?.manifest;
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
67
|
+
const assets = [];
|
|
68
|
+
matches.value.forEach((match) => {
|
|
69
|
+
(manifest?.routes[match.routeId])?.css?.forEach((link) => {
|
|
70
|
+
const resolvedLink = resolveManifestCssLink(link);
|
|
71
|
+
assets.push({
|
|
74
72
|
tag: "link",
|
|
75
73
|
attrs: {
|
|
76
|
-
|
|
77
|
-
|
|
74
|
+
rel: "stylesheet",
|
|
75
|
+
...resolvedLink,
|
|
76
|
+
crossOrigin: getAssetCrossOrigin(assetCrossOrigin, "stylesheet") ?? resolvedLink.crossOrigin
|
|
78
77
|
}
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
if (asset.tag === "style") return [{
|
|
82
|
-
tag: "style",
|
|
83
|
-
attrs: asset.attrs,
|
|
84
|
-
children: asset.children,
|
|
85
|
-
...asset.inlineCss ? { inlineCss: true } : {}
|
|
86
|
-
}];
|
|
87
|
-
return [];
|
|
78
|
+
});
|
|
79
|
+
});
|
|
88
80
|
});
|
|
81
|
+
if (manifest?.inlineStyle) assets.push({
|
|
82
|
+
tag: "style",
|
|
83
|
+
attrs: manifest.inlineStyle.attrs,
|
|
84
|
+
children: manifest.inlineStyle.children,
|
|
85
|
+
inlineCss: true
|
|
86
|
+
});
|
|
87
|
+
return assets;
|
|
89
88
|
});
|
|
90
|
-
return () =>
|
|
91
|
-
|
|
92
|
-
...
|
|
93
|
-
|
|
94
|
-
...
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
return
|
|
98
|
-
}
|
|
89
|
+
return () => {
|
|
90
|
+
const tags = [];
|
|
91
|
+
tags.push(...manifestAssets.value);
|
|
92
|
+
appendUniqueUserTags(tags, meta.value);
|
|
93
|
+
tags.push(...preloadMeta.value);
|
|
94
|
+
appendUniqueUserTags(tags, links.value);
|
|
95
|
+
appendUniqueUserTags(tags, headScripts.value);
|
|
96
|
+
return tags;
|
|
97
|
+
};
|
|
99
98
|
};
|
|
100
|
-
function uniqBy(arr, fn) {
|
|
101
|
-
const seen = /* @__PURE__ */ new Set();
|
|
102
|
-
return arr.filter((item) => {
|
|
103
|
-
const key = fn(item);
|
|
104
|
-
if (seen.has(key)) return false;
|
|
105
|
-
seen.add(key);
|
|
106
|
-
return true;
|
|
107
|
-
});
|
|
108
|
-
}
|
|
109
99
|
//#endregion
|
|
110
100
|
export { useTags };
|
|
111
101
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"headContentUtils.js","names":["Vue","escapeHtml","getAssetCrossOrigin","
|
|
1
|
+
{"version":3,"file":"headContentUtils.js","names":["Vue","appendUniqueUserTags","escapeHtml","getAssetCrossOrigin","getScriptPreloadAttrs","resolveManifestCssLink","useStore","useRouter","useTags","assetCrossOrigin","router","matches","stores","value","meta","computed","resultMeta","metaByAttribute","title","map","match","filter","Boolean","reverse","forEach","metas","m","tag","children","json","JSON","stringify","push","attrs","type","attribute","name","property","links","flat","link","preloadMeta","ssr","manifest","routes","routeId","preloads","preload","headScripts","script","manifestAssets","assets","routeManifest","css","resolvedLink","rel","crossOrigin","inlineStyle","inlineCss","tags"],"sources":["../../src/headContentUtils.tsx"],"sourcesContent":["import * as Vue from 'vue'\nimport {\n appendUniqueUserTags,\n escapeHtml,\n getAssetCrossOrigin,\n getScriptPreloadAttrs,\n resolveManifestCssLink,\n} from '@tanstack/router-core'\nimport { useStore } from '@tanstack/vue-store'\nimport { useRouter } from './useRouter'\nimport type {\n AssetCrossOriginConfig,\n RouterManagedTag,\n} from '@tanstack/router-core'\n\nexport const useTags = (assetCrossOrigin?: AssetCrossOriginConfig) => {\n const router = useRouter()\n const matches = useStore(router.stores.matches, (value) => value)\n\n const meta = Vue.computed<Array<RouterManagedTag>>(() => {\n const resultMeta: Array<RouterManagedTag> = []\n const metaByAttribute: Record<string, true> = {}\n let title: RouterManagedTag | undefined\n ;[...matches.value.map((match) => match.meta!).filter(Boolean)]\n .reverse()\n .forEach((metas) => {\n ;[...metas].reverse().forEach((m) => {\n if (!m) return\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 return\n } else {\n metaByAttribute[attribute] = true\n }\n }\n\n resultMeta.push({\n tag: 'meta',\n attrs: {\n ...m,\n },\n })\n }\n })\n })\n\n if (title) {\n resultMeta.push(title)\n }\n\n resultMeta.reverse()\n\n return resultMeta\n })\n\n const links = Vue.computed<Array<RouterManagedTag>>(\n () =>\n matches.value\n .map((match) => match.links!)\n .filter(Boolean)\n .flat(1)\n .map((link) => ({\n tag: 'link',\n attrs: {\n ...link,\n },\n })) as Array<RouterManagedTag>,\n )\n\n const preloadMeta = Vue.computed<Array<RouterManagedTag>>(() => {\n const preloadMeta: Array<RouterManagedTag> = []\n\n matches.value.forEach((match) => {\n router.ssr?.manifest?.routes[match.routeId]?.preloads\n ?.filter(Boolean)\n .forEach((preload) => {\n preloadMeta.push({\n tag: 'link',\n attrs: {\n ...getScriptPreloadAttrs(\n router.ssr?.manifest,\n preload,\n assetCrossOrigin,\n ),\n },\n })\n })\n })\n\n return preloadMeta\n })\n\n const headScripts = Vue.computed<Array<RouterManagedTag>>(() =>\n (\n matches.value\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 },\n children,\n })),\n )\n\n const manifestAssets = Vue.computed<Array<RouterManagedTag>>(() => {\n const manifest = router.ssr?.manifest\n\n const assets: Array<RouterManagedTag> = []\n\n matches.value.forEach((match) => {\n const routeManifest = manifest?.routes[match.routeId]\n\n routeManifest?.css?.forEach((link) => {\n const resolvedLink = resolveManifestCssLink(link)\n assets.push({\n tag: 'link',\n attrs: {\n rel: 'stylesheet',\n ...resolvedLink,\n crossOrigin:\n getAssetCrossOrigin(assetCrossOrigin, 'stylesheet') ??\n resolvedLink.crossOrigin,\n },\n })\n })\n })\n\n if (manifest?.inlineStyle) {\n assets.push({\n tag: 'style',\n attrs: manifest.inlineStyle.attrs,\n children: manifest.inlineStyle.children,\n inlineCss: true,\n })\n }\n\n return assets\n })\n\n return () => {\n const tags: Array<RouterManagedTag> = []\n tags.push(...manifestAssets.value)\n appendUniqueUserTags(tags, meta.value)\n tags.push(...preloadMeta.value)\n appendUniqueUserTags(tags, links.value)\n appendUniqueUserTags(tags, headScripts.value)\n return tags\n }\n}\n"],"mappings":"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"}
|
|
@@ -12,9 +12,9 @@ export declare const HeadContent: Vue.DefineComponent<Vue.ExtractPropTypes<{
|
|
|
12
12
|
type: Vue.PropType<AssetCrossOriginConfig>;
|
|
13
13
|
default: undefined;
|
|
14
14
|
};
|
|
15
|
-
}>, () => Vue.VNode<Vue.RendererNode, Vue.RendererElement, {
|
|
15
|
+
}>, () => (Vue.VNode<Vue.RendererNode, Vue.RendererElement, {
|
|
16
16
|
[key: string]: any;
|
|
17
|
-
}>[], {}, {}, {}, Vue.ComponentOptionsMixin, Vue.ComponentOptionsMixin, {}, string, Vue.PublicProps, Readonly<Vue.ExtractPropTypes<{
|
|
17
|
+
}> | null)[], {}, {}, {}, Vue.ComponentOptionsMixin, Vue.ComponentOptionsMixin, {}, string, Vue.PublicProps, Readonly<Vue.ExtractPropTypes<{
|
|
18
18
|
assetCrossOrigin: {
|
|
19
19
|
type: Vue.PropType<AssetCrossOriginConfig>;
|
|
20
20
|
default: undefined;
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import * as Vue from 'vue';
|
|
2
|
+
import { DEV_STYLES_ATTR } from '@tanstack/router-core';
|
|
2
3
|
import { Asset } from './Asset';
|
|
3
4
|
import { useHydrated } from './ClientOnly';
|
|
4
5
|
import { useTags } from './headContentUtils';
|
|
5
|
-
const DEV_STYLES_ATTR = 'data-tanstack-router-dev-styles';
|
|
6
6
|
/**
|
|
7
7
|
* @description The `HeadContent` component is used to render meta tags, links, and scripts for the current route.
|
|
8
8
|
* It should be rendered in the `<head>` of your document.
|
|
@@ -29,7 +29,7 @@ export const HeadContent = Vue.defineComponent({
|
|
|
29
29
|
return () => {
|
|
30
30
|
// Filter out dev styles after hydration
|
|
31
31
|
const filteredTags = hydrated.value
|
|
32
|
-
? tags().filter((tag) =>
|
|
32
|
+
? tags().filter((tag) => tag.tag !== 'link' || tag.attrs?.[DEV_STYLES_ATTR] !== true)
|
|
33
33
|
: tags();
|
|
34
34
|
return filteredTags.map((tag) => Vue.h(Asset, {
|
|
35
35
|
...tag,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"HeadContent.dev.jsx","sourceRoot":"","sources":["../../src/HeadContent.dev.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,GAAG,MAAM,KAAK,CAAA;
|
|
1
|
+
{"version":3,"file":"HeadContent.dev.jsx","sourceRoot":"","sources":["../../src/HeadContent.dev.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,GAAG,MAAM,KAAK,CAAA;AAC1B,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAA;AAEvD,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAA;AAC/B,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAA;AAC1C,OAAO,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAA;AAG5C;;;;;GAKG;AACH,MAAM,CAAC,MAAM,WAAW,GAAG,GAAG,CAAC,eAAe,CAAC;IAC7C,IAAI,EAAE,aAAa;IACnB,KAAK,EAAE;QACL,gBAAgB,EAAE;YAChB,IAAI,EAAE,CAAC,MAAM,EAAE,MAAM,CAAyC;YAC9D,OAAO,EAAE,SAAS;SACnB;KACF;IACD,KAAK,CAAC,KAAK;QACT,MAAM,IAAI,GAAG,OAAO,CAAC,KAAK,CAAC,gBAAgB,CAAC,CAAA;QAC5C,MAAM,QAAQ,GAAG,WAAW,EAAE,CAAA;QAE9B,gDAAgD;QAChD,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE;YACjB,QAAQ;iBACL,gBAAgB,CAAC,QAAQ,eAAe,GAAG,CAAC;iBAC5C,OAAO,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,CAAA;QACjC,CAAC,CAAC,CAAA;QAEF,OAAO,GAAG,EAAE;YACV,wCAAwC;YACxC,MAAM,YAAY,GAAG,QAAQ,CAAC,KAAK;gBACjC,CAAC,CAAC,IAAI,EAAE,CAAC,MAAM,CACX,CAAC,GAAG,EAAE,EAAE,CACN,GAAG,CAAC,GAAG,KAAK,MAAM,IAAI,GAAG,CAAC,KAAK,EAAE,CAAC,eAAe,CAAC,KAAK,IAAI,CAC9D;gBACH,CAAC,CAAC,IAAI,EAAE,CAAA;YAEV,OAAO,YAAY,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAC9B,GAAG,CAAC,CAAC,CAAC,KAAK,EAAE;gBACX,GAAG,GAAG;gBACN,GAAG,EAAE,YAAY,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,EAAE;aACvC,CAAC,CACH,CAAA;QACH,CAAC,CAAA;IACH,CAAC;CACF,CAAC,CAAA"}
|