UNPKG

nuxt

Version:

Nuxt is a free and open-source framework with an intuitive and extendable way to create type-safe, performant and production-grade full-stack web applications and websites with Vue.js.

291 lines (290 loc) 7.21 kB
import { defineComponent, inject, onUnmounted, provide, reactive } from "vue"; import { useHead } from "#app/composables/head"; const HeadComponentCtxSymbol = Symbol("head-component"); const TagPositionProps = { /** * @deprecated Use tagPosition */ body: { type: Boolean, default: void 0 }, tagPosition: { type: String } }; const normalizeProps = (_props) => { const props = Object.fromEntries( Object.entries(_props).filter(([_, value]) => value !== void 0) ); if (typeof props.body !== "undefined") { props.tagPosition = props.body ? "bodyClose" : "head"; } if (typeof props.renderPriority !== "undefined") { props.tagPriority = props.renderPriority; } return props; }; function useHeadComponentCtx() { return inject(HeadComponentCtxSymbol, createHeadComponentCtx, true); } function createHeadComponentCtx() { const prev = inject(HeadComponentCtxSymbol, null); if (prev) { return prev; } const input = reactive({}); const entry = useHead(input); const ctx = { input, entry }; provide(HeadComponentCtxSymbol, ctx); return ctx; } const globalProps = { accesskey: String, autocapitalize: String, autofocus: { type: Boolean, default: void 0 }, class: { type: [String, Object, Array], default: void 0 }, contenteditable: { type: Boolean, default: void 0 }, contextmenu: String, dir: String, draggable: { type: Boolean, default: void 0 }, enterkeyhint: String, exportparts: String, hidden: { type: Boolean, default: void 0 }, id: String, inputmode: String, is: String, itemid: String, itemprop: String, itemref: String, itemscope: String, itemtype: String, lang: String, nonce: String, part: String, slot: String, spellcheck: { type: Boolean, default: void 0 }, style: { type: [String, Object, Array], default: void 0 }, tabindex: String, title: String, translate: String, /** * @deprecated Use tagPriority */ renderPriority: [String, Number], /** * Unhead prop to modify the priority of the tag. */ tagPriority: { type: [String, Number] } }; export const NoScript = defineComponent({ name: "NoScript", inheritAttrs: false, props: { ...globalProps, ...TagPositionProps, title: String }, setup(props, { slots }) { const { input } = useHeadComponentCtx(); input.noscript ||= []; const idx = input.noscript.push({}) - 1; onUnmounted(() => input.noscript[idx] = null); return () => { const noscript = normalizeProps(props); const slotVnodes = slots.default?.(); const textContent = slotVnodes ? slotVnodes.filter(({ children }) => children).map(({ children }) => children).join("") : ""; if (textContent) { noscript.innerHTML = textContent; } input.noscript[idx] = noscript; return null; }; } }); export const Link = defineComponent({ name: "Link", inheritAttrs: false, props: { ...globalProps, ...TagPositionProps, as: String, crossorigin: String, disabled: Boolean, fetchpriority: String, href: String, hreflang: String, imagesizes: String, imagesrcset: String, integrity: String, media: String, prefetch: { type: Boolean, default: void 0 }, referrerpolicy: String, rel: String, sizes: String, title: String, type: String, /** @deprecated **/ methods: String, /** @deprecated **/ target: String }, setup(props) { const { input } = useHeadComponentCtx(); input.link ||= []; const idx = input.link.push({}) - 1; onUnmounted(() => input.link[idx] = null); return () => { input.link[idx] = normalizeProps(props); return null; }; } }); export const Base = defineComponent({ name: "Base", inheritAttrs: false, props: { ...globalProps, href: String, target: String }, setup(props) { const { input } = useHeadComponentCtx(); onUnmounted(() => input.base = null); return () => { input.base = normalizeProps(props); return null; }; } }); export const Title = defineComponent({ name: "Title", inheritAttrs: false, setup(_, { slots }) { const { input } = useHeadComponentCtx(); onUnmounted(() => input.title = null); return () => { const defaultSlot = slots.default?.(); input.title = defaultSlot?.[0]?.children ? String(defaultSlot?.[0]?.children) : void 0; if (import.meta.dev) { if (defaultSlot && (defaultSlot.length > 1 || defaultSlot[0] && typeof defaultSlot[0].children !== "string")) { console.error("<Title> can take only one string in its default slot."); } } return null; }; } }); export const Meta = defineComponent({ name: "Meta", inheritAttrs: false, props: { ...globalProps, charset: String, content: String, httpEquiv: String, name: String, property: String }, setup(props) { const { input } = useHeadComponentCtx(); input.meta ||= []; const idx = input.meta.push({}) - 1; onUnmounted(() => input.meta[idx] = null); return () => { const meta = { "http-equiv": props.httpEquiv, ...normalizeProps(props) }; if ("httpEquiv" in meta) { delete meta.httpEquiv; } input.meta[idx] = meta; return null; }; } }); export const Style = defineComponent({ name: "Style", inheritAttrs: false, props: { ...globalProps, ...TagPositionProps, type: String, media: String, nonce: String, title: String, /** @deprecated **/ scoped: { type: Boolean, default: void 0 } }, setup(props, { slots }) { const { input } = useHeadComponentCtx(); input.style ||= []; const idx = input.style.push({}) - 1; onUnmounted(() => input.style[idx] = null); return () => { const style = normalizeProps(props); const textContent = slots.default?.()?.[0]?.children; if (textContent) { if (import.meta.dev && typeof textContent !== "string") { console.error("<Style> can only take a string in its default slot."); } input.style[idx] = style; style.textContent = textContent; } return null; }; } }); export const Head = defineComponent({ name: "Head", inheritAttrs: false, setup: (_props, ctx) => { createHeadComponentCtx(); return () => ctx.slots.default?.(); } }); export const Html = defineComponent({ name: "Html", inheritAttrs: false, props: { ...globalProps, manifest: String, version: String, xmlns: String }, setup(_props, ctx) { const { input } = useHeadComponentCtx(); onUnmounted(() => input.htmlAttrs = null); return () => { input.htmlAttrs = { ..._props, ...ctx.attrs }; return ctx.slots.default?.(); }; } }); export const Body = defineComponent({ name: "Body", inheritAttrs: false, props: globalProps, setup(_props, ctx) { const { input } = useHeadComponentCtx(); onUnmounted(() => input.bodyAttrs = null); return () => { input.bodyAttrs = { ..._props, ...ctx.attrs }; return ctx.slots.default?.(); }; } });