@unhead/vue 0.1.4 → 0.2.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/index.cjs +214 -40
- package/dist/index.d.ts +34 -16
- package/dist/index.mjs +195 -34
- package/package.json +4 -4
- package/dist/runtime/server/index.d.ts +0 -2
- package/dist/runtime/server/index.mjs +0 -2
- package/dist/runtime/server/useHead.d.ts +0 -3
- package/dist/runtime/server/useHead.mjs +0 -5
- package/dist/runtime/server/useServerHead.d.ts +0 -3
- package/dist/runtime/server/useServerHead.mjs +0 -4
- package/dist/runtimes/client/index.d.ts +0 -2
- package/dist/runtimes/client/index.mjs +0 -2
- package/dist/runtimes/client/useHead.d.ts +0 -3
- package/dist/runtimes/client/useHead.mjs +0 -24
- package/dist/runtimes/client/useServerHead.d.ts +0 -3
- package/dist/runtimes/client/useServerHead.mjs +0 -2
package/dist/index.cjs
CHANGED
|
@@ -26,21 +26,16 @@ function asArray(value) {
|
|
|
26
26
|
return Array.isArray(value) ? value : [value];
|
|
27
27
|
}
|
|
28
28
|
|
|
29
|
-
const VueTriggerDomPatchingOnUpdatesPlugin = () => {
|
|
29
|
+
const VueTriggerDomPatchingOnUpdatesPlugin = (options) => {
|
|
30
30
|
return unhead.defineHeadPlugin({
|
|
31
31
|
hooks: {
|
|
32
32
|
"entries:updated": function(head) {
|
|
33
|
-
dom.debouncedRenderDOMHead(vue.nextTick, head);
|
|
33
|
+
dom.debouncedRenderDOMHead(vue.nextTick, head, { document: options?.document });
|
|
34
34
|
}
|
|
35
35
|
}
|
|
36
36
|
});
|
|
37
37
|
};
|
|
38
38
|
|
|
39
|
-
const vueTriggerDomPatchingOnUpdatesPlugin = {
|
|
40
|
-
__proto__: null,
|
|
41
|
-
VueTriggerDomPatchingOnUpdatesPlugin: VueTriggerDomPatchingOnUpdatesPlugin
|
|
42
|
-
};
|
|
43
|
-
|
|
44
39
|
const VueReactiveInputPlugin = () => {
|
|
45
40
|
return unhead.defineHeadPlugin({
|
|
46
41
|
hooks: {
|
|
@@ -52,20 +47,151 @@ const VueReactiveInputPlugin = () => {
|
|
|
52
47
|
});
|
|
53
48
|
};
|
|
54
49
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
const
|
|
50
|
+
function unpackToArray(input, options) {
|
|
51
|
+
const unpacked = [];
|
|
52
|
+
const kFn = options.resolveKeyData || ((ctx) => ctx.key);
|
|
53
|
+
const vFn = options.resolveValueData || ((ctx) => ctx.value);
|
|
54
|
+
for (const [k, v] of Object.entries(input)) {
|
|
55
|
+
unpacked.push(...(Array.isArray(v) ? v : [v]).map((i) => {
|
|
56
|
+
const ctx = { key: k, value: i };
|
|
57
|
+
const val = vFn(ctx);
|
|
58
|
+
if (typeof val === "object")
|
|
59
|
+
return unpackToArray(val, options);
|
|
60
|
+
if (Array.isArray(val))
|
|
61
|
+
return val;
|
|
62
|
+
return {
|
|
63
|
+
[typeof options.key === "function" ? options.key(ctx) : options.key]: kFn(ctx),
|
|
64
|
+
[typeof options.value === "function" ? options.value(ctx) : options.value]: val
|
|
65
|
+
};
|
|
66
|
+
}).flat());
|
|
67
|
+
}
|
|
68
|
+
return unpacked;
|
|
69
|
+
}
|
|
58
70
|
|
|
59
|
-
function
|
|
60
|
-
|
|
61
|
-
|
|
71
|
+
function unpackToString(value, options) {
|
|
72
|
+
return Object.entries(value).map(([key, value2]) => {
|
|
73
|
+
if (typeof value2 === "object")
|
|
74
|
+
value2 = unpackToString(value2, options);
|
|
75
|
+
if (options.resolve) {
|
|
76
|
+
const resolved = options.resolve({ key, value: value2 });
|
|
77
|
+
if (resolved)
|
|
78
|
+
return resolved;
|
|
79
|
+
}
|
|
80
|
+
if (typeof value2 === "number")
|
|
81
|
+
value2 = value2.toString();
|
|
82
|
+
if (typeof value2 === "string" && options.wrapValue) {
|
|
83
|
+
value2 = value2.replace(new RegExp(options.wrapValue, "g"), `\\${options.wrapValue}`);
|
|
84
|
+
value2 = `${options.wrapValue}${value2}${options.wrapValue}`;
|
|
85
|
+
}
|
|
86
|
+
return `${key}${options.keyValueSeparator || ""}${value2}`;
|
|
87
|
+
}).join(options.entrySeparator || "");
|
|
62
88
|
}
|
|
63
89
|
|
|
64
|
-
|
|
65
|
-
|
|
90
|
+
const MetaPackingSchema = {
|
|
91
|
+
robots: {
|
|
92
|
+
unpack: {
|
|
93
|
+
keyValueSeparator: ":"
|
|
94
|
+
}
|
|
95
|
+
},
|
|
96
|
+
contentSecurityPolicy: {
|
|
97
|
+
unpack: {
|
|
98
|
+
keyValueSeparator: " ",
|
|
99
|
+
entrySeparator: "; "
|
|
100
|
+
},
|
|
101
|
+
metaKey: "http-equiv"
|
|
102
|
+
},
|
|
103
|
+
fbAppId: {
|
|
104
|
+
keyValue: "fb:app_id",
|
|
105
|
+
metaKey: "property"
|
|
106
|
+
},
|
|
107
|
+
msapplicationTileImage: {
|
|
108
|
+
keyValue: "msapplication-TileImage"
|
|
109
|
+
},
|
|
110
|
+
msapplicationTileColor: {
|
|
111
|
+
keyValue: "msapplication-TileColor"
|
|
112
|
+
},
|
|
113
|
+
msapplicationConfig: {
|
|
114
|
+
keyValue: "msapplication-Config"
|
|
115
|
+
},
|
|
116
|
+
charset: {
|
|
117
|
+
metaKey: "charset"
|
|
118
|
+
},
|
|
119
|
+
contentType: {
|
|
120
|
+
metaKey: "http-equiv"
|
|
121
|
+
},
|
|
122
|
+
defaultStyle: {
|
|
123
|
+
metaKey: "http-equiv"
|
|
124
|
+
},
|
|
125
|
+
xUaCompatible: {
|
|
126
|
+
metaKey: "http-equiv"
|
|
127
|
+
},
|
|
128
|
+
refresh: {
|
|
129
|
+
metaKey: "http-equiv"
|
|
130
|
+
}
|
|
131
|
+
};
|
|
132
|
+
function resolveMetaKeyType(key) {
|
|
133
|
+
return PropertyPrefixKeys.test(key) ? "property" : MetaPackingSchema[key]?.metaKey || "name";
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
function unpackMeta(input) {
|
|
137
|
+
return unpackToArray(input, {
|
|
138
|
+
key({ key }) {
|
|
139
|
+
return resolveMetaKeyType(key);
|
|
140
|
+
},
|
|
141
|
+
value({ key }) {
|
|
142
|
+
return key === "charset" ? "charset" : "content";
|
|
143
|
+
},
|
|
144
|
+
resolveKeyData({ key }) {
|
|
145
|
+
return MetaPackingSchema[key]?.keyValue || fixKeyCase(key);
|
|
146
|
+
},
|
|
147
|
+
resolveValueData({ value, key }) {
|
|
148
|
+
if (typeof value === "object") {
|
|
149
|
+
const definition = MetaPackingSchema[key];
|
|
150
|
+
if (key === "refresh")
|
|
151
|
+
return `${value.seconds};url=${value.url}`;
|
|
152
|
+
return unpackToString(
|
|
153
|
+
changeKeyCasingDeep(value),
|
|
154
|
+
{
|
|
155
|
+
entrySeparator: ", ",
|
|
156
|
+
keyValueSeparator: "=",
|
|
157
|
+
resolve({ value: value2, key: key2 }) {
|
|
158
|
+
if (typeof value2 === "boolean")
|
|
159
|
+
return `${key2}`;
|
|
160
|
+
},
|
|
161
|
+
...definition?.unpack
|
|
162
|
+
}
|
|
163
|
+
);
|
|
164
|
+
}
|
|
165
|
+
return typeof value === "number" ? value.toString() : value;
|
|
166
|
+
}
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
const PropertyPrefixKeys = /^(og|twitter|fb)/;
|
|
171
|
+
function fixKeyCase(key) {
|
|
172
|
+
key = key.replace(/([A-Z])/g, "-$1").toLowerCase();
|
|
173
|
+
if (PropertyPrefixKeys.test(key)) {
|
|
174
|
+
key = key.replace("secure-url", "secure_url").replace(/-/g, ":");
|
|
175
|
+
}
|
|
176
|
+
return key;
|
|
66
177
|
}
|
|
178
|
+
function changeKeyCasingDeep(input) {
|
|
179
|
+
if (Array.isArray(input)) {
|
|
180
|
+
return input.map((entry) => changeKeyCasingDeep(entry));
|
|
181
|
+
}
|
|
182
|
+
if (typeof input !== "object" || Array.isArray(input))
|
|
183
|
+
return input;
|
|
184
|
+
const output = {};
|
|
185
|
+
for (const [key, value] of Object.entries(input))
|
|
186
|
+
output[fixKeyCase(key)] = changeKeyCasingDeep(value);
|
|
187
|
+
return output;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
const Vue3 = vue.version.startsWith("3");
|
|
191
|
+
vue.version.startsWith("2.");
|
|
192
|
+
const IsBrowser = typeof window !== "undefined";
|
|
67
193
|
|
|
68
|
-
function
|
|
194
|
+
function clientUseHead(input, options = {}) {
|
|
69
195
|
const head = injectHead();
|
|
70
196
|
const vm = vue.getCurrentInstance();
|
|
71
197
|
if (!vm) {
|
|
@@ -88,41 +214,66 @@ function useHead$1(input, options = {}) {
|
|
|
88
214
|
});
|
|
89
215
|
}
|
|
90
216
|
|
|
217
|
+
function serverUseHead(input, options = {}) {
|
|
218
|
+
const head = injectHead();
|
|
219
|
+
head.push(input, options);
|
|
220
|
+
}
|
|
221
|
+
|
|
91
222
|
function useServerHead(input, options = {}) {
|
|
92
|
-
|
|
93
|
-
useServerHead$1(input, options);
|
|
223
|
+
useHead(input, { ...options, mode: "server" });
|
|
94
224
|
}
|
|
225
|
+
const useServerTagTitle = (title) => useServerHead({ title });
|
|
226
|
+
const useServerTitleTemplate = (titleTemplate) => useServerHead({ titleTemplate });
|
|
227
|
+
const useServerTagMeta = (meta) => useServerHead({ meta: asArray(meta) });
|
|
228
|
+
const useServerTagMetaFlat = (meta) => {
|
|
229
|
+
const input = vue.ref({});
|
|
230
|
+
vue.watchEffect(() => {
|
|
231
|
+
input.value = unpackMeta(resolveUnrefHeadInput(meta));
|
|
232
|
+
});
|
|
233
|
+
return useServerHead({ meta: input });
|
|
234
|
+
};
|
|
235
|
+
const useServerTagLink = (link) => useServerHead({ link: asArray(link) });
|
|
236
|
+
const useServerTagScript = (script) => useServerHead({ script: asArray(script) });
|
|
237
|
+
const useServerTagStyle = (style) => useServerHead({ style: asArray(style) });
|
|
238
|
+
const useServerTagNoscript = (noscript) => useServerHead({ noscript: asArray(noscript) });
|
|
239
|
+
const useServerTagBase = (base) => useServerHead({ base });
|
|
240
|
+
const useServerHtmlAttrs = (attrs) => useServerHead({ htmlAttrs: attrs });
|
|
241
|
+
const useServerBodyAttrs = (attrs) => useHead({ bodyAttrs: attrs });
|
|
242
|
+
|
|
95
243
|
function useHead(input, options = {}) {
|
|
96
244
|
if (options.mode === "server" && IsBrowser || options.mode === "client" && !IsBrowser)
|
|
97
245
|
return;
|
|
98
|
-
IsBrowser ?
|
|
246
|
+
IsBrowser ? clientUseHead(input, options) : serverUseHead(input, options);
|
|
99
247
|
}
|
|
100
|
-
const
|
|
248
|
+
const useTagTitle = (title) => useHead({ title });
|
|
101
249
|
const useTitleTemplate = (titleTemplate) => useHead({ titleTemplate });
|
|
102
|
-
const
|
|
103
|
-
const
|
|
104
|
-
const
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
250
|
+
const useTagMeta = (meta) => useHead({ meta: asArray(meta) });
|
|
251
|
+
const useTagMetaFlat = (meta) => {
|
|
252
|
+
const input = vue.ref({});
|
|
253
|
+
vue.watchEffect(() => {
|
|
254
|
+
input.value = unpackMeta(resolveUnrefHeadInput(meta));
|
|
255
|
+
});
|
|
256
|
+
return useHead({ meta: input });
|
|
257
|
+
};
|
|
258
|
+
const useTagLink = (link) => useHead({ link: asArray(link) });
|
|
259
|
+
const useTagScript = (script) => useHead({ script: asArray(script) });
|
|
260
|
+
const useTagStyle = (style) => useHead({ style: asArray(style) });
|
|
261
|
+
const useTagNoscript = (noscript) => useHead({ noscript: asArray(noscript) });
|
|
262
|
+
const useTagBase = (base) => useHead({ base });
|
|
108
263
|
const useHtmlAttrs = (attrs) => useHead({ htmlAttrs: attrs });
|
|
109
264
|
const useBodyAttrs = (attrs) => useHead({ bodyAttrs: attrs });
|
|
110
265
|
|
|
111
|
-
const headSymbol =
|
|
266
|
+
const headSymbol = "usehead";
|
|
112
267
|
function injectHead() {
|
|
113
268
|
return vue.getCurrentInstance() && vue.inject(headSymbol) || unhead.getActiveHead();
|
|
114
269
|
}
|
|
115
|
-
|
|
270
|
+
function createHead(options = {}) {
|
|
116
271
|
const plugins = [
|
|
117
272
|
unhead.HydratesStatePlugin(),
|
|
118
273
|
VueReactiveInputPlugin(),
|
|
119
274
|
...options?.plugins || []
|
|
120
275
|
];
|
|
121
|
-
|
|
122
|
-
const { VueTriggerDomPatchingOnUpdatesPlugin } = await Promise.resolve().then(function () { return vueTriggerDomPatchingOnUpdatesPlugin; });
|
|
123
|
-
plugins.push(VueTriggerDomPatchingOnUpdatesPlugin());
|
|
124
|
-
}
|
|
125
|
-
const head = await unhead.createHead({
|
|
276
|
+
const head = unhead.createHead({
|
|
126
277
|
...options,
|
|
127
278
|
plugins
|
|
128
279
|
});
|
|
@@ -148,6 +299,16 @@ async function createHead(options = {}) {
|
|
|
148
299
|
return { ...vuePlugin, ...head };
|
|
149
300
|
}
|
|
150
301
|
|
|
302
|
+
function createDomHead(options = {}) {
|
|
303
|
+
return createHead({
|
|
304
|
+
...options,
|
|
305
|
+
plugins: [
|
|
306
|
+
VueTriggerDomPatchingOnUpdatesPlugin({ document: options?.document }),
|
|
307
|
+
...options.plugins || []
|
|
308
|
+
]
|
|
309
|
+
});
|
|
310
|
+
}
|
|
311
|
+
|
|
151
312
|
const HeadVuePlugin = function(_Vue) {
|
|
152
313
|
_Vue.mixin({
|
|
153
314
|
beforeCreate() {
|
|
@@ -178,21 +339,34 @@ exports.HeadVuePlugin = HeadVuePlugin;
|
|
|
178
339
|
exports.VueReactiveInputPlugin = VueReactiveInputPlugin;
|
|
179
340
|
exports.VueTriggerDomPatchingOnUpdatesPlugin = VueTriggerDomPatchingOnUpdatesPlugin;
|
|
180
341
|
exports.asArray = asArray;
|
|
342
|
+
exports.createDomHead = createDomHead;
|
|
181
343
|
exports.createHead = createHead;
|
|
182
344
|
exports.headSymbol = headSymbol;
|
|
183
345
|
exports.injectHead = injectHead;
|
|
184
346
|
exports.resolveUnrefHeadInput = resolveUnrefHeadInput;
|
|
185
|
-
exports.useBase = useBase;
|
|
186
347
|
exports.useBodyAttrs = useBodyAttrs;
|
|
187
348
|
exports.useHead = useHead;
|
|
188
349
|
exports.useHtmlAttrs = useHtmlAttrs;
|
|
189
|
-
exports.
|
|
190
|
-
exports.useMeta = useMeta;
|
|
191
|
-
exports.useNoscript = useNoscript;
|
|
192
|
-
exports.useScript = useScript;
|
|
350
|
+
exports.useServerBodyAttrs = useServerBodyAttrs;
|
|
193
351
|
exports.useServerHead = useServerHead;
|
|
194
|
-
exports.
|
|
195
|
-
exports.
|
|
352
|
+
exports.useServerHtmlAttrs = useServerHtmlAttrs;
|
|
353
|
+
exports.useServerTagBase = useServerTagBase;
|
|
354
|
+
exports.useServerTagLink = useServerTagLink;
|
|
355
|
+
exports.useServerTagMeta = useServerTagMeta;
|
|
356
|
+
exports.useServerTagMetaFlat = useServerTagMetaFlat;
|
|
357
|
+
exports.useServerTagNoscript = useServerTagNoscript;
|
|
358
|
+
exports.useServerTagScript = useServerTagScript;
|
|
359
|
+
exports.useServerTagStyle = useServerTagStyle;
|
|
360
|
+
exports.useServerTagTitle = useServerTagTitle;
|
|
361
|
+
exports.useServerTitleTemplate = useServerTitleTemplate;
|
|
362
|
+
exports.useTagBase = useTagBase;
|
|
363
|
+
exports.useTagLink = useTagLink;
|
|
364
|
+
exports.useTagMeta = useTagMeta;
|
|
365
|
+
exports.useTagMetaFlat = useTagMetaFlat;
|
|
366
|
+
exports.useTagNoscript = useTagNoscript;
|
|
367
|
+
exports.useTagScript = useTagScript;
|
|
368
|
+
exports.useTagStyle = useTagStyle;
|
|
369
|
+
exports.useTagTitle = useTagTitle;
|
|
196
370
|
exports.useTitleTemplate = useTitleTemplate;
|
|
197
371
|
for (const k in dom) {
|
|
198
372
|
if (k !== 'default' && !exports.hasOwnProperty(k)) exports[k] = dom[k];
|
package/dist/index.d.ts
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { MaybeComputedRef, MaybeRef } from '@vueuse/shared';
|
|
2
2
|
export { MaybeComputedRef } from '@vueuse/shared';
|
|
3
3
|
import * as _unhead_schema from '@unhead/schema';
|
|
4
|
-
import { Title as Title$1, TitleTemplate as TitleTemplate$1, EntryAugmentation, Base as Base$1, Link as Link$1, Meta as Meta$1, Style as Style$1, Script as Script$1, Noscript as Noscript$1, DataKeys, SchemaAugmentations, DefinedValueOrEmptyObject, MergeHead, BaseHtmlAttr, MaybeArray, BaseBodyAttr, HeadEntryOptions, HeadClient, CreateHeadOptions } from '@unhead/schema';
|
|
4
|
+
import { Title as Title$1, TitleTemplate as TitleTemplate$1, EntryAugmentation, Base as Base$1, Link as Link$1, Meta as Meta$1, Style as Style$1, Script as Script$1, Noscript as Noscript$1, DataKeys, SchemaAugmentations, DefinedValueOrEmptyObject, MergeHead, BaseHtmlAttr, MaybeArray, BaseBodyAttr, HeadEntryOptions, MetaFlatInput, HeadClient, CreateHeadOptions } from '@unhead/schema';
|
|
5
5
|
export { ActiveHeadEntry, Head, HeadClient, HeadEntryOptions, HeadTag, MergeHead } from '@unhead/schema';
|
|
6
|
-
import {
|
|
6
|
+
import { RenderDomHeadOptions } from '@unhead/dom';
|
|
7
7
|
export * from '@unhead/dom';
|
|
8
|
+
import { Plugin } from 'vue';
|
|
8
9
|
|
|
9
10
|
declare type MaybeComputedRefEntries<T> = MaybeComputedRef<T> | {
|
|
10
11
|
[key in keyof T]?: MaybeComputedRef<T[key]>;
|
|
@@ -103,33 +104,50 @@ interface ReactiveHead<E extends MergeHead = MergeHead> {
|
|
|
103
104
|
*/
|
|
104
105
|
bodyAttrs?: BodyAttributes<E['bodyAttrs']>;
|
|
105
106
|
}
|
|
106
|
-
declare type UseHeadInput = MaybeComputedRef<ReactiveHead
|
|
107
|
+
declare type UseHeadInput<T extends MergeHead = {}> = MaybeComputedRef<ReactiveHead<T>>;
|
|
107
108
|
|
|
108
109
|
declare function resolveUnrefHeadInput(ref: any): any;
|
|
109
110
|
declare function asArray<T>(value: Arrayable<T>): T[];
|
|
110
111
|
|
|
111
|
-
declare const VueTriggerDomPatchingOnUpdatesPlugin: () => _unhead_schema.HeadPlugin;
|
|
112
|
+
declare const VueTriggerDomPatchingOnUpdatesPlugin: (options?: RenderDomHeadOptions) => _unhead_schema.HeadPlugin;
|
|
112
113
|
|
|
113
114
|
declare const VueReactiveInputPlugin: () => _unhead_schema.HeadPlugin;
|
|
114
115
|
|
|
115
|
-
declare function useServerHead(input:
|
|
116
|
-
declare
|
|
117
|
-
declare const
|
|
116
|
+
declare function useServerHead<T extends MergeHead>(input: UseHeadInput<T>, options?: HeadEntryOptions): void;
|
|
117
|
+
declare const useServerTagTitle: (title: ReactiveHead['title']) => void;
|
|
118
|
+
declare const useServerTitleTemplate: (titleTemplate: ReactiveHead['titleTemplate']) => void;
|
|
119
|
+
declare const useServerTagMeta: (meta: Arrayable<Meta>) => void;
|
|
120
|
+
declare const useServerTagMetaFlat: (meta: MaybeComputedRefEntries<MetaFlatInput>) => void;
|
|
121
|
+
declare const useServerTagLink: (link: Arrayable<Link>) => void;
|
|
122
|
+
declare const useServerTagScript: (script: Arrayable<Script>) => void;
|
|
123
|
+
declare const useServerTagStyle: (style: Arrayable<Style>) => void;
|
|
124
|
+
declare const useServerTagNoscript: (noscript: Arrayable<Noscript>) => void;
|
|
125
|
+
declare const useServerTagBase: (base: ReactiveHead['base']) => void;
|
|
126
|
+
declare const useServerHtmlAttrs: (attrs: ReactiveHead['htmlAttrs']) => void;
|
|
127
|
+
declare const useServerBodyAttrs: (attrs: ReactiveHead['bodyAttrs']) => void;
|
|
128
|
+
|
|
129
|
+
declare function useHead<T extends MergeHead>(input: UseHeadInput<T>, options?: HeadEntryOptions): void;
|
|
130
|
+
declare const useTagTitle: (title: ReactiveHead['title']) => void;
|
|
118
131
|
declare const useTitleTemplate: (titleTemplate: ReactiveHead['titleTemplate']) => void;
|
|
119
|
-
declare const
|
|
120
|
-
declare const
|
|
121
|
-
declare const
|
|
122
|
-
declare const
|
|
123
|
-
declare const
|
|
124
|
-
declare const
|
|
132
|
+
declare const useTagMeta: (meta: Arrayable<Meta>) => void;
|
|
133
|
+
declare const useTagMetaFlat: (meta: MaybeComputedRefEntries<MetaFlatInput>) => void;
|
|
134
|
+
declare const useTagLink: (link: Arrayable<Link>) => void;
|
|
135
|
+
declare const useTagScript: (script: Arrayable<Script>) => void;
|
|
136
|
+
declare const useTagStyle: (style: Arrayable<Style>) => void;
|
|
137
|
+
declare const useTagNoscript: (noscript: Arrayable<Noscript>) => void;
|
|
138
|
+
declare const useTagBase: (base: ReactiveHead['base']) => void;
|
|
125
139
|
declare const useHtmlAttrs: (attrs: ReactiveHead['htmlAttrs']) => void;
|
|
126
140
|
declare const useBodyAttrs: (attrs: ReactiveHead['bodyAttrs']) => void;
|
|
127
141
|
|
|
128
142
|
declare type VueHeadClient<T extends MergeHead> = HeadClient<MaybeComputedRef<ReactiveHead<T>>> & Plugin;
|
|
129
|
-
declare const headSymbol
|
|
143
|
+
declare const headSymbol = "usehead";
|
|
130
144
|
declare function injectHead<T extends MergeHead>(): VueHeadClient<T>;
|
|
131
|
-
declare function createHead<T extends MergeHead>(options?: CreateHeadOptions):
|
|
145
|
+
declare function createHead<T extends MergeHead>(options?: CreateHeadOptions): VueHeadClient<T>;
|
|
146
|
+
|
|
147
|
+
declare function createDomHead<T extends MergeHead>(options?: CreateHeadOptions & {
|
|
148
|
+
document?: Document;
|
|
149
|
+
}): VueHeadClient<T>;
|
|
132
150
|
|
|
133
151
|
declare const HeadVuePlugin: Plugin;
|
|
134
152
|
|
|
135
|
-
export { Arrayable, Base, BodyAttributes, HeadVuePlugin, HtmlAttributes, Link, MaybeComputedRefEntries, Meta, Noscript, ReactiveHead, Script, Style, Title, TitleTemplate, UseHeadInput, VueHeadClient, VueReactiveInputPlugin, VueTriggerDomPatchingOnUpdatesPlugin, asArray, createHead, headSymbol, injectHead, resolveUnrefHeadInput,
|
|
153
|
+
export { Arrayable, Base, BodyAttributes, HeadVuePlugin, HtmlAttributes, Link, MaybeComputedRefEntries, Meta, Noscript, ReactiveHead, Script, Style, Title, TitleTemplate, UseHeadInput, VueHeadClient, VueReactiveInputPlugin, VueTriggerDomPatchingOnUpdatesPlugin, asArray, createDomHead, createHead, headSymbol, injectHead, resolveUnrefHeadInput, useBodyAttrs, useHead, useHtmlAttrs, useServerBodyAttrs, useServerHead, useServerHtmlAttrs, useServerTagBase, useServerTagLink, useServerTagMeta, useServerTagMetaFlat, useServerTagNoscript, useServerTagScript, useServerTagStyle, useServerTagTitle, useServerTitleTemplate, useTagBase, useTagLink, useTagMeta, useTagMetaFlat, useTagNoscript, useTagScript, useTagStyle, useTagTitle, useTitleTemplate };
|
package/dist/index.mjs
CHANGED
|
@@ -25,21 +25,16 @@ function asArray(value) {
|
|
|
25
25
|
return Array.isArray(value) ? value : [value];
|
|
26
26
|
}
|
|
27
27
|
|
|
28
|
-
const VueTriggerDomPatchingOnUpdatesPlugin = () => {
|
|
28
|
+
const VueTriggerDomPatchingOnUpdatesPlugin = (options) => {
|
|
29
29
|
return defineHeadPlugin({
|
|
30
30
|
hooks: {
|
|
31
31
|
"entries:updated": function(head) {
|
|
32
|
-
debouncedRenderDOMHead(nextTick, head);
|
|
32
|
+
debouncedRenderDOMHead(nextTick, head, { document: options?.document });
|
|
33
33
|
}
|
|
34
34
|
}
|
|
35
35
|
});
|
|
36
36
|
};
|
|
37
37
|
|
|
38
|
-
const vueTriggerDomPatchingOnUpdatesPlugin = {
|
|
39
|
-
__proto__: null,
|
|
40
|
-
VueTriggerDomPatchingOnUpdatesPlugin: VueTriggerDomPatchingOnUpdatesPlugin
|
|
41
|
-
};
|
|
42
|
-
|
|
43
38
|
const VueReactiveInputPlugin = () => {
|
|
44
39
|
return defineHeadPlugin({
|
|
45
40
|
hooks: {
|
|
@@ -51,20 +46,151 @@ const VueReactiveInputPlugin = () => {
|
|
|
51
46
|
});
|
|
52
47
|
};
|
|
53
48
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
const
|
|
49
|
+
function unpackToArray(input, options) {
|
|
50
|
+
const unpacked = [];
|
|
51
|
+
const kFn = options.resolveKeyData || ((ctx) => ctx.key);
|
|
52
|
+
const vFn = options.resolveValueData || ((ctx) => ctx.value);
|
|
53
|
+
for (const [k, v] of Object.entries(input)) {
|
|
54
|
+
unpacked.push(...(Array.isArray(v) ? v : [v]).map((i) => {
|
|
55
|
+
const ctx = { key: k, value: i };
|
|
56
|
+
const val = vFn(ctx);
|
|
57
|
+
if (typeof val === "object")
|
|
58
|
+
return unpackToArray(val, options);
|
|
59
|
+
if (Array.isArray(val))
|
|
60
|
+
return val;
|
|
61
|
+
return {
|
|
62
|
+
[typeof options.key === "function" ? options.key(ctx) : options.key]: kFn(ctx),
|
|
63
|
+
[typeof options.value === "function" ? options.value(ctx) : options.value]: val
|
|
64
|
+
};
|
|
65
|
+
}).flat());
|
|
66
|
+
}
|
|
67
|
+
return unpacked;
|
|
68
|
+
}
|
|
57
69
|
|
|
58
|
-
function
|
|
59
|
-
|
|
60
|
-
|
|
70
|
+
function unpackToString(value, options) {
|
|
71
|
+
return Object.entries(value).map(([key, value2]) => {
|
|
72
|
+
if (typeof value2 === "object")
|
|
73
|
+
value2 = unpackToString(value2, options);
|
|
74
|
+
if (options.resolve) {
|
|
75
|
+
const resolved = options.resolve({ key, value: value2 });
|
|
76
|
+
if (resolved)
|
|
77
|
+
return resolved;
|
|
78
|
+
}
|
|
79
|
+
if (typeof value2 === "number")
|
|
80
|
+
value2 = value2.toString();
|
|
81
|
+
if (typeof value2 === "string" && options.wrapValue) {
|
|
82
|
+
value2 = value2.replace(new RegExp(options.wrapValue, "g"), `\\${options.wrapValue}`);
|
|
83
|
+
value2 = `${options.wrapValue}${value2}${options.wrapValue}`;
|
|
84
|
+
}
|
|
85
|
+
return `${key}${options.keyValueSeparator || ""}${value2}`;
|
|
86
|
+
}).join(options.entrySeparator || "");
|
|
61
87
|
}
|
|
62
88
|
|
|
63
|
-
|
|
64
|
-
|
|
89
|
+
const MetaPackingSchema = {
|
|
90
|
+
robots: {
|
|
91
|
+
unpack: {
|
|
92
|
+
keyValueSeparator: ":"
|
|
93
|
+
}
|
|
94
|
+
},
|
|
95
|
+
contentSecurityPolicy: {
|
|
96
|
+
unpack: {
|
|
97
|
+
keyValueSeparator: " ",
|
|
98
|
+
entrySeparator: "; "
|
|
99
|
+
},
|
|
100
|
+
metaKey: "http-equiv"
|
|
101
|
+
},
|
|
102
|
+
fbAppId: {
|
|
103
|
+
keyValue: "fb:app_id",
|
|
104
|
+
metaKey: "property"
|
|
105
|
+
},
|
|
106
|
+
msapplicationTileImage: {
|
|
107
|
+
keyValue: "msapplication-TileImage"
|
|
108
|
+
},
|
|
109
|
+
msapplicationTileColor: {
|
|
110
|
+
keyValue: "msapplication-TileColor"
|
|
111
|
+
},
|
|
112
|
+
msapplicationConfig: {
|
|
113
|
+
keyValue: "msapplication-Config"
|
|
114
|
+
},
|
|
115
|
+
charset: {
|
|
116
|
+
metaKey: "charset"
|
|
117
|
+
},
|
|
118
|
+
contentType: {
|
|
119
|
+
metaKey: "http-equiv"
|
|
120
|
+
},
|
|
121
|
+
defaultStyle: {
|
|
122
|
+
metaKey: "http-equiv"
|
|
123
|
+
},
|
|
124
|
+
xUaCompatible: {
|
|
125
|
+
metaKey: "http-equiv"
|
|
126
|
+
},
|
|
127
|
+
refresh: {
|
|
128
|
+
metaKey: "http-equiv"
|
|
129
|
+
}
|
|
130
|
+
};
|
|
131
|
+
function resolveMetaKeyType(key) {
|
|
132
|
+
return PropertyPrefixKeys.test(key) ? "property" : MetaPackingSchema[key]?.metaKey || "name";
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
function unpackMeta(input) {
|
|
136
|
+
return unpackToArray(input, {
|
|
137
|
+
key({ key }) {
|
|
138
|
+
return resolveMetaKeyType(key);
|
|
139
|
+
},
|
|
140
|
+
value({ key }) {
|
|
141
|
+
return key === "charset" ? "charset" : "content";
|
|
142
|
+
},
|
|
143
|
+
resolveKeyData({ key }) {
|
|
144
|
+
return MetaPackingSchema[key]?.keyValue || fixKeyCase(key);
|
|
145
|
+
},
|
|
146
|
+
resolveValueData({ value, key }) {
|
|
147
|
+
if (typeof value === "object") {
|
|
148
|
+
const definition = MetaPackingSchema[key];
|
|
149
|
+
if (key === "refresh")
|
|
150
|
+
return `${value.seconds};url=${value.url}`;
|
|
151
|
+
return unpackToString(
|
|
152
|
+
changeKeyCasingDeep(value),
|
|
153
|
+
{
|
|
154
|
+
entrySeparator: ", ",
|
|
155
|
+
keyValueSeparator: "=",
|
|
156
|
+
resolve({ value: value2, key: key2 }) {
|
|
157
|
+
if (typeof value2 === "boolean")
|
|
158
|
+
return `${key2}`;
|
|
159
|
+
},
|
|
160
|
+
...definition?.unpack
|
|
161
|
+
}
|
|
162
|
+
);
|
|
163
|
+
}
|
|
164
|
+
return typeof value === "number" ? value.toString() : value;
|
|
165
|
+
}
|
|
166
|
+
});
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
const PropertyPrefixKeys = /^(og|twitter|fb)/;
|
|
170
|
+
function fixKeyCase(key) {
|
|
171
|
+
key = key.replace(/([A-Z])/g, "-$1").toLowerCase();
|
|
172
|
+
if (PropertyPrefixKeys.test(key)) {
|
|
173
|
+
key = key.replace("secure-url", "secure_url").replace(/-/g, ":");
|
|
174
|
+
}
|
|
175
|
+
return key;
|
|
65
176
|
}
|
|
177
|
+
function changeKeyCasingDeep(input) {
|
|
178
|
+
if (Array.isArray(input)) {
|
|
179
|
+
return input.map((entry) => changeKeyCasingDeep(entry));
|
|
180
|
+
}
|
|
181
|
+
if (typeof input !== "object" || Array.isArray(input))
|
|
182
|
+
return input;
|
|
183
|
+
const output = {};
|
|
184
|
+
for (const [key, value] of Object.entries(input))
|
|
185
|
+
output[fixKeyCase(key)] = changeKeyCasingDeep(value);
|
|
186
|
+
return output;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
const Vue3 = version.startsWith("3");
|
|
190
|
+
version.startsWith("2.");
|
|
191
|
+
const IsBrowser = typeof window !== "undefined";
|
|
66
192
|
|
|
67
|
-
function
|
|
193
|
+
function clientUseHead(input, options = {}) {
|
|
68
194
|
const head = injectHead();
|
|
69
195
|
const vm = getCurrentInstance();
|
|
70
196
|
if (!vm) {
|
|
@@ -87,41 +213,66 @@ function useHead$1(input, options = {}) {
|
|
|
87
213
|
});
|
|
88
214
|
}
|
|
89
215
|
|
|
216
|
+
function serverUseHead(input, options = {}) {
|
|
217
|
+
const head = injectHead();
|
|
218
|
+
head.push(input, options);
|
|
219
|
+
}
|
|
220
|
+
|
|
90
221
|
function useServerHead(input, options = {}) {
|
|
91
|
-
|
|
92
|
-
useServerHead$1(input, options);
|
|
222
|
+
useHead(input, { ...options, mode: "server" });
|
|
93
223
|
}
|
|
224
|
+
const useServerTagTitle = (title) => useServerHead({ title });
|
|
225
|
+
const useServerTitleTemplate = (titleTemplate) => useServerHead({ titleTemplate });
|
|
226
|
+
const useServerTagMeta = (meta) => useServerHead({ meta: asArray(meta) });
|
|
227
|
+
const useServerTagMetaFlat = (meta) => {
|
|
228
|
+
const input = ref({});
|
|
229
|
+
watchEffect(() => {
|
|
230
|
+
input.value = unpackMeta(resolveUnrefHeadInput(meta));
|
|
231
|
+
});
|
|
232
|
+
return useServerHead({ meta: input });
|
|
233
|
+
};
|
|
234
|
+
const useServerTagLink = (link) => useServerHead({ link: asArray(link) });
|
|
235
|
+
const useServerTagScript = (script) => useServerHead({ script: asArray(script) });
|
|
236
|
+
const useServerTagStyle = (style) => useServerHead({ style: asArray(style) });
|
|
237
|
+
const useServerTagNoscript = (noscript) => useServerHead({ noscript: asArray(noscript) });
|
|
238
|
+
const useServerTagBase = (base) => useServerHead({ base });
|
|
239
|
+
const useServerHtmlAttrs = (attrs) => useServerHead({ htmlAttrs: attrs });
|
|
240
|
+
const useServerBodyAttrs = (attrs) => useHead({ bodyAttrs: attrs });
|
|
241
|
+
|
|
94
242
|
function useHead(input, options = {}) {
|
|
95
243
|
if (options.mode === "server" && IsBrowser || options.mode === "client" && !IsBrowser)
|
|
96
244
|
return;
|
|
97
|
-
IsBrowser ?
|
|
245
|
+
IsBrowser ? clientUseHead(input, options) : serverUseHead(input, options);
|
|
98
246
|
}
|
|
99
|
-
const
|
|
247
|
+
const useTagTitle = (title) => useHead({ title });
|
|
100
248
|
const useTitleTemplate = (titleTemplate) => useHead({ titleTemplate });
|
|
101
|
-
const
|
|
102
|
-
const
|
|
103
|
-
const
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
249
|
+
const useTagMeta = (meta) => useHead({ meta: asArray(meta) });
|
|
250
|
+
const useTagMetaFlat = (meta) => {
|
|
251
|
+
const input = ref({});
|
|
252
|
+
watchEffect(() => {
|
|
253
|
+
input.value = unpackMeta(resolveUnrefHeadInput(meta));
|
|
254
|
+
});
|
|
255
|
+
return useHead({ meta: input });
|
|
256
|
+
};
|
|
257
|
+
const useTagLink = (link) => useHead({ link: asArray(link) });
|
|
258
|
+
const useTagScript = (script) => useHead({ script: asArray(script) });
|
|
259
|
+
const useTagStyle = (style) => useHead({ style: asArray(style) });
|
|
260
|
+
const useTagNoscript = (noscript) => useHead({ noscript: asArray(noscript) });
|
|
261
|
+
const useTagBase = (base) => useHead({ base });
|
|
107
262
|
const useHtmlAttrs = (attrs) => useHead({ htmlAttrs: attrs });
|
|
108
263
|
const useBodyAttrs = (attrs) => useHead({ bodyAttrs: attrs });
|
|
109
264
|
|
|
110
|
-
const headSymbol =
|
|
265
|
+
const headSymbol = "usehead";
|
|
111
266
|
function injectHead() {
|
|
112
267
|
return getCurrentInstance() && inject(headSymbol) || getActiveHead();
|
|
113
268
|
}
|
|
114
|
-
|
|
269
|
+
function createHead(options = {}) {
|
|
115
270
|
const plugins = [
|
|
116
271
|
HydratesStatePlugin(),
|
|
117
272
|
VueReactiveInputPlugin(),
|
|
118
273
|
...options?.plugins || []
|
|
119
274
|
];
|
|
120
|
-
|
|
121
|
-
const { VueTriggerDomPatchingOnUpdatesPlugin } = await Promise.resolve().then(function () { return vueTriggerDomPatchingOnUpdatesPlugin; });
|
|
122
|
-
plugins.push(VueTriggerDomPatchingOnUpdatesPlugin());
|
|
123
|
-
}
|
|
124
|
-
const head = await createHead$1({
|
|
275
|
+
const head = createHead$1({
|
|
125
276
|
...options,
|
|
126
277
|
plugins
|
|
127
278
|
});
|
|
@@ -147,6 +298,16 @@ async function createHead(options = {}) {
|
|
|
147
298
|
return { ...vuePlugin, ...head };
|
|
148
299
|
}
|
|
149
300
|
|
|
301
|
+
function createDomHead(options = {}) {
|
|
302
|
+
return createHead({
|
|
303
|
+
...options,
|
|
304
|
+
plugins: [
|
|
305
|
+
VueTriggerDomPatchingOnUpdatesPlugin({ document: options?.document }),
|
|
306
|
+
...options.plugins || []
|
|
307
|
+
]
|
|
308
|
+
});
|
|
309
|
+
}
|
|
310
|
+
|
|
150
311
|
const HeadVuePlugin = function(_Vue) {
|
|
151
312
|
_Vue.mixin({
|
|
152
313
|
beforeCreate() {
|
|
@@ -173,4 +334,4 @@ const HeadVuePlugin = function(_Vue) {
|
|
|
173
334
|
});
|
|
174
335
|
};
|
|
175
336
|
|
|
176
|
-
export { HeadVuePlugin, VueReactiveInputPlugin, VueTriggerDomPatchingOnUpdatesPlugin, asArray, createHead, headSymbol, injectHead, resolveUnrefHeadInput,
|
|
337
|
+
export { HeadVuePlugin, VueReactiveInputPlugin, VueTriggerDomPatchingOnUpdatesPlugin, asArray, createDomHead, createHead, headSymbol, injectHead, resolveUnrefHeadInput, useBodyAttrs, useHead, useHtmlAttrs, useServerBodyAttrs, useServerHead, useServerHtmlAttrs, useServerTagBase, useServerTagLink, useServerTagMeta, useServerTagMetaFlat, useServerTagNoscript, useServerTagScript, useServerTagStyle, useServerTagTitle, useServerTitleTemplate, useTagBase, useTagLink, useTagMeta, useTagMetaFlat, useTagNoscript, useTagScript, useTagStyle, useTagTitle, useTitleTemplate };
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@unhead/vue",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.2.3",
|
|
5
5
|
"packageManager": "pnpm@7.14.0",
|
|
6
6
|
"author": "Harlan Wilton <harlan@harlanzw.com>",
|
|
7
7
|
"license": "MIT",
|
|
@@ -33,10 +33,10 @@
|
|
|
33
33
|
"vue": ">=2.7 || >=3"
|
|
34
34
|
},
|
|
35
35
|
"dependencies": {
|
|
36
|
-
"@unhead/dom": "0.
|
|
37
|
-
"@unhead/schema": "0.
|
|
36
|
+
"@unhead/dom": "0.2.3",
|
|
37
|
+
"@unhead/schema": "0.2.3",
|
|
38
38
|
"@vueuse/shared": "latest",
|
|
39
|
-
"unhead": "0.
|
|
39
|
+
"unhead": "0.2.3"
|
|
40
40
|
},
|
|
41
41
|
"devDependencies": {
|
|
42
42
|
"vue": "latest"
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
import { getCurrentInstance, onBeforeUnmount, ref, watch, watchEffect } from "vue";
|
|
2
|
-
import { injectHead, resolveUnrefHeadInput } from "../../index";
|
|
3
|
-
export function useHead(input, options = {}) {
|
|
4
|
-
const head = injectHead();
|
|
5
|
-
const vm = getCurrentInstance();
|
|
6
|
-
if (!vm) {
|
|
7
|
-
head.push(input, options);
|
|
8
|
-
return;
|
|
9
|
-
}
|
|
10
|
-
const resolvedInput = ref({});
|
|
11
|
-
watchEffect(() => {
|
|
12
|
-
resolvedInput.value = resolveUnrefHeadInput(input);
|
|
13
|
-
});
|
|
14
|
-
let entry;
|
|
15
|
-
watch(resolvedInput, (e) => {
|
|
16
|
-
if (!entry)
|
|
17
|
-
entry = head.push(e, options);
|
|
18
|
-
else
|
|
19
|
-
entry.patch(e);
|
|
20
|
-
}, { immediate: true });
|
|
21
|
-
onBeforeUnmount(() => {
|
|
22
|
-
entry?.dispose();
|
|
23
|
-
});
|
|
24
|
-
}
|