UNPKG

@storyblok/richtext

Version:
257 lines (256 loc) 9.42 kB
/** * name: @storyblok/richtext * (c) 2025 * description: Storyblok RichText Resolver * author: Alvaro Saburido <hola@alvarosaburido.dev> (https://github.com/alvarosabu/) */ function k(e, n) { if (!n) return { src: e, attrs: {} }; let m = 0, S = 0; const g = {}, c = []; function v(l, E, $, L, I) { typeof l != "number" || l <= E || l >= $ ? console.warn(`[StoryblokRichText] - ${L.charAt(0).toUpperCase() + L.slice(1)} value must be a number between ${E} and ${$} (inclusive)`) : I.push(`${L}(${l})`); } if (typeof n == "object") { if (typeof n.width == "number" && n.width > 0 ? (g.width = n.width, m = n.width) : console.warn("[StoryblokRichText] - Width value must be a number greater than 0"), n.height && typeof n.height == "number" && n.height > 0 ? (g.height = n.height, S = n.height) : console.warn("[StoryblokRichText] - Height value must be a number greater than 0"), n.loading && ["lazy", "eager"].includes(n.loading) && (g.loading = n.loading), n.class && (g.class = n.class), n.filters) { const { filters: l } = n || {}, { blur: E, brightness: $, fill: L, format: I, grayscale: R, quality: O, rotate: C } = l || {}; E && v(E, 0, 100, "blur", c), O && v(O, 0, 100, "quality", c), $ && v($, 0, 100, "brightness", c), L && c.push(`fill(${L})`), R && c.push("grayscale()"), C && [0, 90, 180, 270].includes(n.filters.rotate || 0) && c.push(`rotate(${C})`), I && ["webp", "png", "jpeg"].includes(I) && c.push(`format(${I})`); } n.srcset && (g.srcset = n.srcset.map((l) => { if (typeof l == "number") return `${e}/m/${l}x0/${c.length > 0 ? `filters:${c.join(":")}` : ""} ${l}w`; if (Array.isArray(l) && l.length === 2) { const [E, $] = l; return `${e}/m/${E}x${$}/${c.length > 0 ? `filters:${c.join(":")}` : ""} ${E}w`; } else { console.warn("[StoryblokRichText] - srcset entry must be a number or a tuple of two numbers"); return; } }).join(", ")), n.sizes && (g.sizes = n.sizes.join(", ")); } let A = `${e}/m/`; return m > 0 && S > 0 && (A = `${A}${m}x${S}/`), c.length > 0 && (A = `${A}filters:${c.join(":")}`), { src: A, attrs: g }; } var f = /* @__PURE__ */ ((e) => (e.DOCUMENT = "doc", e.HEADING = "heading", e.PARAGRAPH = "paragraph", e.QUOTE = "blockquote", e.OL_LIST = "ordered_list", e.UL_LIST = "bullet_list", e.LIST_ITEM = "list_item", e.CODE_BLOCK = "code_block", e.HR = "horizontal_rule", e.BR = "hard_break", e.IMAGE = "image", e.EMOJI = "emoji", e.COMPONENT = "blok", e.TABLE = "table", e.TABLE_ROW = "tableRow", e.TABLE_CELL = "tableCell", e.TABLE_HEADER = "tableHeader", e))(f || {}), b = /* @__PURE__ */ ((e) => (e.BOLD = "bold", e.STRONG = "strong", e.STRIKE = "strike", e.UNDERLINE = "underline", e.ITALIC = "italic", e.CODE = "code", e.LINK = "link", e.ANCHOR = "anchor", e.STYLED = "styled", e.SUPERSCRIPT = "superscript", e.SUBSCRIPT = "subscript", e.TEXT_STYLE = "textStyle", e.HIGHLIGHT = "highlight", e))(b || {}), y = /* @__PURE__ */ ((e) => (e.TEXT = "text", e))(y || {}), B = /* @__PURE__ */ ((e) => (e.SELF = "_self", e.BLANK = "_blank", e))(B || {}), w = /* @__PURE__ */ ((e) => (e.URL = "url", e.STORY = "story", e.ASSET = "asset", e.EMAIL = "email", e))(w || {}); const W = [ "area", "base", "br", "col", "embed", "hr", "img", "input", "link", "meta", "param", "source", "track", "wbr" ], X = (e = {}) => Object.keys(e).map((n) => `${n}="${e[n]}"`).join(" "), M = (e = {}) => Object.keys(e).map((n) => `${n}: ${e[n]}`).join("; "); function J(e) { return e.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&#039;"); } const x = (e) => Object.fromEntries(Object.entries(e).filter(([n, m]) => m !== void 0)); function H(e, n = {}, m) { const S = X(n), g = S ? `${e} ${S}` : e, c = Array.isArray(m) ? m.join("") : m || ""; if (e) { if (W.includes(e)) return `<${g}>`; } else return c; return `<${g}>${c}</${e}>`; } function Q(e = {}) { const n = /* @__PURE__ */ new Map(), { renderFn: m = H, textFn: S = J, resolvers: g = {}, optimizeImages: c = !1, keyedResolvers: v = !1 } = e, A = m !== H, l = (t) => (s, r) => { const a = s.attrs || {}; return r.render(t, a, s.children || null); }, E = (t, s) => { const { src: r, alt: a, title: i, srcset: o, sizes: u } = t.attrs || {}; let d = r, h = {}; if (c) { const { src: Y, attrs: q } = k(r, c); d = Y, h = q; } const K = { src: d, alt: a, title: i, srcset: o, sizes: u, ...h }; return s.render("img", x(K)); }, $ = (t, s) => { const { level: r, ...a } = t.attrs || {}; return s.render(`h${r}`, a, t.children); }, L = (t, s) => { var a, i, o, u; const r = s.render("img", { src: (a = t.attrs) == null ? void 0 : a.fallbackImage, alt: (i = t.attrs) == null ? void 0 : i.alt, style: "width: 1.25em; height: 1.25em; vertical-align: text-top", draggable: "false", loading: "lazy" }); return s.render("span", { "data-type": "emoji", "data-name": (o = t.attrs) == null ? void 0 : o.name, "data-emoji": (u = t.attrs) == null ? void 0 : u.emoji }, r); }, I = (t, s) => s.render( "pre", t.attrs || {}, s.render("code", {}, t.children || "") ), R = (t, s = !1) => ({ text: r, attrs: a }, i) => { const { class: o, id: u, ...d } = a || {}, h = s ? { class: o, id: u, style: M(d) || void 0 } : a || {}; return i.render(t, x(h), r); }, O = (t) => _(t), C = (t) => { const { marks: s, ...r } = t; if ("text" in t) { if (s) return s.reduce( (i, o) => O({ ...o, text: i }), O({ ...r, children: r.children }) ); const a = t.attrs || {}; if (v) { const i = n.get("txt") || 0; n.set("txt", i + 1), a.key = `txt-${i}`; } return S(r.text, a); } return ""; }, j = (t, s) => { const { linktype: r, href: a, anchor: i, ...o } = t.attrs || {}; let u = ""; switch (r) { case w.ASSET: case w.URL: u = a; break; case w.EMAIL: u = `mailto:${a}`; break; case w.STORY: u = a, i && (u = `${u}#${i}`); break; default: u = a; break; } const d = { ...o }; return u && (d.href = u), s.render("a", d, t.text); }, D = (t, s) => { var r, a; return console.warn("[StoryblokRichtText] - BLOK resolver is not available for vanilla usage"), s.render("span", { blok: (r = t == null ? void 0 : t.attrs) == null ? void 0 : r.body[0], id: (a = t.attrs) == null ? void 0 : a.id, style: "display: none" }); }, P = (t, s) => { const r = {}, a = s.render("tbody", {}, t.children); return s.render("table", r, a); }, U = (t, s) => { const r = {}; return s.render("tr", r, t.children); }, G = (t, s) => { const { colspan: r, rowspan: a, colwidth: i, backgroundColor: o, ...u } = t.attrs || {}, d = { ...u }; r > 1 && (d.colspan = r), a > 1 && (d.rowspan = a); const h = []; return i && h.push(`width: ${i}px;`), o && h.push(`background-color: ${o};`), h.length > 0 && (d.style = h.join(" ")), s.render("td", x(d), t.children); }, z = (t, s) => { const { colspan: r, rowspan: a, colwidth: i, backgroundColor: o, ...u } = t.attrs || {}, d = { ...u }; r > 1 && (d.colspan = r), a > 1 && (d.rowspan = a); const h = []; return i && h.push(`width: ${i}px;`), o && h.push(`background-color: ${o};`), h.length > 0 && (d.style = h.join(" ")), s.render("th", x(d), t.children); }, p = /* @__PURE__ */ new Map([ [f.DOCUMENT, l("")], [f.HEADING, $], [f.PARAGRAPH, l("p")], [f.UL_LIST, l("ul")], [f.OL_LIST, l("ol")], [f.LIST_ITEM, l("li")], [f.IMAGE, E], [f.EMOJI, L], [f.CODE_BLOCK, I], [f.HR, l("hr")], [f.BR, l("br")], [f.QUOTE, l("blockquote")], [f.COMPONENT, D], [y.TEXT, C], [b.LINK, j], [b.ANCHOR, j], [b.STYLED, R("span", !0)], [b.BOLD, R("strong")], [b.TEXT_STYLE, R("span", !0)], [b.ITALIC, R("em")], [b.UNDERLINE, R("u")], [b.STRIKE, R("s")], [b.CODE, R("code")], [b.SUPERSCRIPT, R("sup")], [b.SUBSCRIPT, R("sub")], [b.HIGHLIGHT, R("mark")], [f.TABLE, P], [f.TABLE_ROW, U], [f.TABLE_CELL, G], [f.TABLE_HEADER, z] ]), N = new Map([ ...p, ...Object.entries(g).map(([t, s]) => [t, s]) ]), F = () => ({ render: (r, a = {}, i) => { if (v && r) { const o = n.get(r) || 0; n.set(r, o + 1), a.key = `${r}-${o}`; } return m(r, a, i); }, originalResolvers: p, mergedResolvers: N }); function T(t) { const s = N.get(t.type); if (!s) return console.error("<Storyblok>", `No resolver found for node type ${t.type}`), ""; const r = F(); if (t.type === "text") return s(t, r); const a = t.content ? t.content.map(_) : void 0; return s({ ...t, children: a }, r); } function _(t) { return t.type === "doc" ? A ? t.content.map(T) : t.content.map(T).join("") : Array.isArray(t) ? t.map(T) : T(t); } return { render: _ }; } export { f as BlockTypes, B as LinkTargets, w as LinkTypes, b as MarkTypes, y as TextTypes, Q as richTextResolver };