UNPKG

contentful-rich-text-vue-renderer

Version:
147 lines (133 loc) 5.31 kB
'use strict'; var richTextTypes = require('@contentful/rich-text-types'); var vue = require('vue'); const defaultInline = (type, node, key) => { return vue.h( "span", { key, style: { margin: "0px 5px", padding: "0 .25rem 0 .75rem", border: "1px solid #d3dce0", fontFamily: "monospace", }, }, `inline: ${type}, sys.id: ${node.data.target.sys.id}` ); }; const defaultMarkRenderers = { [richTextTypes.MARKS.BOLD]: (children, key) => vue.h("strong", { key }, children), [richTextTypes.MARKS.ITALIC]: (children, key) => vue.h("em", { key }, children), [richTextTypes.MARKS.UNDERLINE]: (children, key) => vue.h("u", { key }, children), [richTextTypes.MARKS.CODE]: (children, key) => vue.h("code", { key }, children), [richTextTypes.MARKS.SUPERSCRIPT]: (children, key) => vue.h("sup", { key }, children), [richTextTypes.MARKS.SUBSCRIPT]: (children, key) => vue.h("sub", { key }, children), [richTextTypes.MARKS.STRIKETHROUGH]: (children, key) => vue.h("s", { key }, children), }; const defaultNodeRenderers = { [richTextTypes.BLOCKS.PARAGRAPH]: (node, key, next) => vue.h("p", { key }, next(node.content, key, next)), [richTextTypes.BLOCKS.HEADING_1]: (node, key, next) => vue.h("h1", { key }, next(node.content, key, next)), [richTextTypes.BLOCKS.HEADING_2]: (node, key, next) => vue.h("h2", { key }, next(node.content, key, next)), [richTextTypes.BLOCKS.HEADING_3]: (node, key, next) => vue.h("h3", { key }, next(node.content, key, next)), [richTextTypes.BLOCKS.HEADING_4]: (node, key, next) => vue.h("h4", { key }, next(node.content, key, next)), [richTextTypes.BLOCKS.HEADING_5]: (node, key, next) => vue.h("h5", { key }, next(node.content, key, next)), [richTextTypes.BLOCKS.HEADING_6]: (node, key, next) => vue.h("h6", { key }, next(node.content, key, next)), [richTextTypes.BLOCKS.EMBEDDED_ENTRY]: (node, key, next) => vue.h("div", { key }, next(node.content, key, next)), [richTextTypes.BLOCKS.UL_LIST]: (node, key, next) => vue.h("ul", { key }, next(node.content, key, next)), [richTextTypes.BLOCKS.OL_LIST]: (node, key, next) => vue.h("ol", { key }, next(node.content, key, next)), [richTextTypes.BLOCKS.LIST_ITEM]: (node, key, next) => vue.h("li", { key }, next(node.content, key, next)), [richTextTypes.BLOCKS.QUOTE]: (node, key, next) => vue.h("blockquote", { key }, next(node.content, key, next)), [richTextTypes.BLOCKS.TABLE]: (node, key, next) => vue.h("table", { key }, next(node.content, key, next)), [richTextTypes.BLOCKS.TABLE_ROW]: (node, key, next) => vue.h("tr", { key }, next(node.content, key, next)), [richTextTypes.BLOCKS.TABLE_CELL]: (node, key, next) => vue.h("td", { key }, next(node.content, key, next)), [richTextTypes.BLOCKS.TABLE_HEADER_CELL]: (node, key, next) => vue.h("th", { key }, next(node.content, key, next)), [richTextTypes.BLOCKS.HR]: (_node, key) => vue.h("hr", { key }), [richTextTypes.INLINES.ASSET_HYPERLINK]: (node, key) => defaultInline(richTextTypes.INLINES.ASSET_HYPERLINK, node, key), [richTextTypes.INLINES.ENTRY_HYPERLINK]: (node, key) => defaultInline(richTextTypes.INLINES.ENTRY_HYPERLINK, node, key), [richTextTypes.INLINES.EMBEDDED_ENTRY]: (node, key) => defaultInline(richTextTypes.INLINES.EMBEDDED_ENTRY, node, key), [richTextTypes.INLINES.HYPERLINK]: (node, key, next) => { return vue.h( "a", { key, href: node.data.uri, }, next(node.content, key, next) ); }, text: ({ marks, value }, key, markRenderer) => { if (!marks.length) { return value; } const marksReversed = [...marks].reverse(); return marksReversed.reduce( (aggregate, mark, i) => markRenderer[mark.type]([aggregate], `${key}-${i}`, vue.h), value ); }, }; const renderNodeList = (nodes, key, renderer) => { return nodes.map((node, i) => renderNode(node, `${key}-${i}`, renderer)); }; const renderNode = (node, key, renderer) => { const nodeRenderer = renderer.node; if (richTextTypes.helpers.isText(node)) { // We're at final tip of node branch, can render text. const markerRender = renderer.mark; return nodeRenderer.text(node, key, markerRender); } else { const nextNode = (nodes) => renderNodeList(nodes, key, renderer); if (!nodeRenderer) { return vue.h("div", { key }, `${key} ;lost nodeRenderer`); } if (!node.nodeType || !nodeRenderer[node.nodeType]) { // TODO: Figure what to return when passed an unrecognized node. return vue.h( "div", { key }, "(Unrecognized node type) " + (node.nodeType || "empty") ); } return nodeRenderer[node.nodeType](node, key, nextNode); } }; const RichText = ({ nodeRenderers, markRenderers, document }) => { if (!document) { console.warn("No document given to RichText renderer"); return []; } const renderer = { node: { ...defaultNodeRenderers, ...nodeRenderers, }, mark: { ...defaultMarkRenderers, ...markRenderers, }, }; return renderNodeList(document.content, "RichText-", renderer); }; RichText.props = ["document", "nodeRenderers", "markRenderers"]; module.exports = RichText;