shelving
Version:
Toolkit for using data in JavaScript.
49 lines (48 loc) • 2.62 kB
JavaScript
import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
import { useEffect } from "react";
import { getProps } from "../../util/object.js";
import { requireMeta } from "../misc/MetaContext.js";
import { joinTitles } from "../util/meta.js";
/** Meta tags with a capital first letter and hyphens, e.g. `Content-Security-Policy` or `Accept`, are `http-equiv=""` tags. */
const R_HTTP_EQUIV = /^[A-Z][a-zA-Z0-9]*(-[A-Z][a-zA-Z0-9]*)*$/;
/**
* Per-page meta tags plus history navigation.
* - Emits hoistable head elements (title, meta, links, stylesheets, scripts) inline; React 19 hoists each one into the document `<head>`.
* - Does not render `<base>` (not hoistable — that lives in `<Head>` in the `<HTML>` shell component).
* - Updates `window.history` to match the page URL.
*/
export function Head() {
const meta = requireMeta();
const { url, title, app, description, links, tags, stylesheets, modules, scripts } = meta;
useEffect(() => {
if (typeof window === "undefined")
return;
if (url)
window.history.replaceState(null, "", url);
}, [url]);
const fullTitle = joinTitles(title, app);
return (_jsxs(_Fragment, { children: [fullTitle && _jsx("title", { children: fullTitle }), description && _jsx("meta", { name: "description", content: description }), tags && getProps(tags).map(_renderTag), links && getProps(links).map(_renderLink), stylesheets?.map(_renderStylesheet), modules?.map(_renderModule), scripts?.map(_renderScript)] }));
}
function _renderTag([k, x]) {
if (x === null || x === undefined)
return null;
const y = x === true ? "yes" : x === false ? "no" : x;
if (k.startsWith("og:"))
return _jsx("meta", { property: k, content: y }, k); // Tags that start with `og:` use `property=""`
if (k.match(R_HTTP_EQUIV))
return _jsx("meta", { httpEquiv: k, content: y }, k); // Tags that are in `Snake-Case` use `http-equiv=""`
return _jsx("meta", { name: k, content: y }, k); // All other tags use `content=""`
}
function _renderLink([k, { href }]) {
const type = k.endsWith("icon") ? "image/x-icon" : "text/css";
return _jsx("link", { rel: k, href: href, type: type }, k);
}
function _renderStylesheet({ href }) {
return _jsx("link", { rel: "stylesheet", type: "text/css", href: href, precedence: "default" }, href);
}
function _renderModule({ href }) {
return _jsx("script", { type: "module", src: href, async: true }, href);
}
function _renderScript({ href }) {
return _jsx("script", { type: "text/javascript", src: href, async: true }, href);
}