UNPKG

@shopify/hydrogen-react

Version:

React components, hooks, and utilities for creating custom Shopify storefronts

161 lines (160 loc) 3.98 kB
import { jsx } from "react/jsx-runtime"; import { useMemo, createElement, Fragment } from "react"; import { RichTextComponents } from "./RichText.components.mjs"; function RichText({ as, data, plain, components, ...passthroughProps }) { try { const Wrapper = as ?? "div"; const parsedData = useMemo( () => JSON.parse(data), [data] ); return /* @__PURE__ */ jsx(Wrapper, { ...passthroughProps, children: plain ? richTextToString(parsedData) : serializeRichTextASTNode(components, parsedData) }); } catch (e) { throw new Error( "[h2:error:RichText] Parsing error. Make sure to pass a JSON string of rich text metafield", { cause: e } ); } } function serializeRichTextASTNode(components = {}, node, index = 0) { let children; if ("children" in node) { children = node.children.map( (child, childIndex) => serializeRichTextASTNode(components, child, childIndex) ); } const Component = components[node.type === "list-item" ? "listItem" : node.type] ?? RichTextComponents[node.type]; switch (node.type) { case "root": return createElement( Component, { key: index, node: { type: "root", children } } ); case "heading": return createElement( Component, { key: index, node: { type: "heading", level: node.level, children } } ); case "paragraph": return createElement( Component, { key: index, node: { type: "paragraph", children } } ); case "text": { const elements = (node.value ?? "").split("\n").flatMap((value, subindex) => { const key = `${index}-${value}-${subindex}`; const textElement = createElement( Component, { key, node: { type: "text", italic: node.italic, bold: node.bold, value } } ); return subindex === 0 ? textElement : [createElement("br", { key: `${key}-br` }), textElement]; }); return elements.length > 1 ? createElement(Fragment, { key: index }, elements) : elements[0]; } case "link": return createElement( Component, { key: index, node: { type: "link", url: node.url, title: node.title, target: node.target, children } } ); case "list": return createElement( Component, { key: index, node: { type: "list", listType: node.listType, children } } ); case "list-item": return createElement( Component, { key: index, node: { type: "list-item", children } } ); } } function richTextToString(node, result = []) { switch (node.type) { case "root": node.children.forEach((child) => richTextToString(child, result)); break; case "heading": case "paragraph": node.children.forEach((child) => richTextToString(child, result)); result.push(" "); break; case "text": result.push(node.value || ""); break; case "link": node.children.forEach((child) => richTextToString(child, result)); break; case "list": node.children.forEach((item) => { if (item.children) { item.children.forEach((child) => richTextToString(child, result)); } result.push(" "); }); break; default: throw new Error(`Unknown node encountered ${node.type}`); } return result.join("").trim(); } export { RichText }; //# sourceMappingURL=RichText.mjs.map