UNPKG

@nacelle/rich-text-utils

Version:

A set of Typescript types and helpers to work with Rich Text fields.

127 lines 5.66 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.genericHtmlRender = exports.render = exports.transformNode = exports.defaultMetaTransformer = exports.markToTagName = exports.renderRule = exports.RenderError = void 0; const guards_1 = require("./guards"); const array_flatten_1 = require("array-flatten"); class RenderError extends Error { constructor(message, node) { super(message); this.node = node; Object.setPrototypeOf(this, RenderError.prototype); } } exports.RenderError = RenderError; const renderRule = (guard, transform) => ({ appliable: guard, apply: (ctx) => transform(ctx) }); exports.renderRule = renderRule; function markToTagName(mark) { switch (mark) { case 'emphasis': return 'em'; case 'underline': return 'u'; case 'strikethrough': return 'del'; case 'highlight': return 'mark'; default: return mark; } } exports.markToTagName = markToTagName; const defaultMetaTransformer = ({ meta }) => { const attributes = {}; meta.forEach((entry) => { if (['target', 'title', 'rel'].includes(entry.id)) { attributes[entry.id] = entry.value; } }); return attributes; }; exports.defaultMetaTransformer = defaultMetaTransformer; function transformNode(adapter, node, key, ancestors, renderRules) { const children = guards_1.hasChildren(node) ? array_flatten_1.flatten(node.children .map((node, index) => transformNode(adapter, node, `t-${index}`, [...ancestors, node], renderRules)) .filter((x) => !!x)) : undefined; const matchingTransform = renderRules.find((transform) => transform.appliable(node)); if (matchingTransform) { return matchingTransform.apply({ adapter, node, children, key, ancestors }); } else { throw new RenderError(`Don't know how to render a node with type "${node.type}". Please specify a custom renderRule for it!`, node); } } exports.transformNode = transformNode; function render(adapter, richTextOrNode, renderRules) { if (!richTextOrNode) { return null; } const result = transformNode(adapter, guards_1.isRichText(richTextOrNode) ? richTextOrNode.value.document : guards_1.isDocument(richTextOrNode) ? richTextOrNode.document : richTextOrNode, 't-0', [], renderRules); return result; } exports.render = render; function genericHtmlRender(adapter, richTextOrNode, customRules, metaTransformer = exports.defaultMetaTransformer) { return render(adapter, richTextOrNode, [ ...customRules, exports.renderRule(guards_1.isRoot, ({ adapter: { renderFragment }, key, children }) => { return renderFragment(children, key); }), exports.renderRule(guards_1.isParagraph, ({ adapter: { renderNode }, key, children }) => { return renderNode('p', { key }, children); }), exports.renderRule(guards_1.isList, ({ adapter: { renderNode }, node, key, children }) => { return renderNode(node.style === 'bulleted' ? 'ul' : 'ol', { key }, children); }), exports.renderRule(guards_1.isListItem, ({ adapter: { renderNode }, key, children }) => { return renderNode('li', { key }, children); }), exports.renderRule(guards_1.isBlockquote, ({ adapter: { renderNode }, key, node, children }) => { const childrenWithAttribution = node.attribution ? [ ...(children || []), renderNode(`footer`, { key: 'footer' }, node.attribution), ] : children; return renderNode('blockquote', { key }, childrenWithAttribution); }), exports.renderRule(guards_1.isCode, ({ adapter: { renderNode, renderText }, key, node }) => { return renderNode('pre', { key, 'data-language': node.language }, renderNode('code', null, renderText(node.code))); }), exports.renderRule(guards_1.isLink, ({ adapter: { renderNode }, key, children, node }) => { const meta = node.meta ? metaTransformer({ node, meta: node.meta }) : {}; return renderNode('a', Object.assign(Object.assign({}, (meta || {})), { key, href: node.url }), children); }), exports.renderRule(guards_1.isThematicBreak, ({ adapter: { renderNode }, key }) => { return renderNode('hr', { key }); }), exports.renderRule(guards_1.isHeading, ({ node, adapter: { renderNode }, children, key }) => { return renderNode(`h${node.level}`, { key }, children); }), exports.renderRule(guards_1.isSpan, ({ adapter: { renderNode, renderText }, key, node }) => { const marks = node.marks || []; const lines = node.value.split(/\n/); const textWithNewlinesConvertedToBr = lines.length > 0 ? lines.slice(1).reduce((acc, line, index) => { return acc.concat([ renderNode('br', { key: `${key}-br-${index}` }), renderText(line, `${key}-line-${index}`), ]); }, [renderText(lines[0], `${key}-line-first`)]) : renderText(node.value, key); return marks.reduce((children, mark) => { return renderNode(markToTagName(mark), { key }, children); }, textWithNewlinesConvertedToBr); }), ]); } exports.genericHtmlRender = genericHtmlRender; ; //# sourceMappingURL=render.js.map