storyblok-rich-text-react-renderer
Version:
A React renderer for Storyblok rich text content
309 lines (305 loc) • 11.1 kB
JavaScript
import React from 'react';
function _defineProperty(e, r, t) {
return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, {
value: t,
enumerable: true,
configurable: true,
writable: true
}) : e[r] = t, e;
}
function ownKeys(e, r) {
var t = Object.keys(e);
if (Object.getOwnPropertySymbols) {
var o = Object.getOwnPropertySymbols(e);
r && (o = o.filter(function (r) {
return Object.getOwnPropertyDescriptor(e, r).enumerable;
})), t.push.apply(t, o);
}
return t;
}
function _objectSpread2(e) {
for (var r = 1; r < arguments.length; r++) {
var t = null != arguments[r] ? arguments[r] : {};
r % 2 ? ownKeys(Object(t), true).forEach(function (r) {
_defineProperty(e, r, t[r]);
}) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) {
Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r));
});
}
return e;
}
function _objectWithoutProperties(e, t) {
if (null == e) return {};
var o,
r,
i = _objectWithoutPropertiesLoose(e, t);
if (Object.getOwnPropertySymbols) {
var n = Object.getOwnPropertySymbols(e);
for (r = 0; r < n.length; r++) o = n[r], -1 === t.indexOf(o) && {}.propertyIsEnumerable.call(e, o) && (i[o] = e[o]);
}
return i;
}
function _objectWithoutPropertiesLoose(r, e) {
if (null == r) return {};
var t = {};
for (var n in r) if ({}.hasOwnProperty.call(r, n)) {
if (-1 !== e.indexOf(n)) continue;
t[n] = r[n];
}
return t;
}
function _toPrimitive(t, r) {
if ("object" != typeof t || !t) return t;
var e = t[Symbol.toPrimitive];
if (void 0 !== e) {
var i = e.call(t, r);
if ("object" != typeof i) return i;
throw new TypeError("@@toPrimitive must return a primitive value.");
}
return ("string" === r ? String : Number)(t);
}
function _toPropertyKey(t) {
var i = _toPrimitive(t, "string");
return "symbol" == typeof i ? i : i + "";
}
const _excluded = ["component"];
const NODE_HEADING = 'heading';
const NODE_CODEBLOCK = 'code_block';
const NODE_PARAGRAPH = 'paragraph';
const NODE_QUOTE = 'blockquote';
const NODE_OL = 'ordered_list';
const NODE_UL = 'bullet_list';
const NODE_LI = 'list_item';
const NODE_HR = 'horizontal_rule';
const NODE_BR = 'hard_break';
const NODE_IMAGE = 'image';
const NODE_EMOJI = 'emoji';
const NODE_TABLE = 'table';
const NODE_TABLE_HEADER = 'tableHeader';
const NODE_TABLE_ROW = 'tableRow';
const NODE_TABLE_CELL = 'tableCell';
const MARK_BOLD = 'bold';
const MARK_ITALIC = 'italic';
const MARK_STRIKE = 'strike';
const MARK_UNDERLINE = 'underline';
const MARK_CODE = 'code';
const MARK_LINK = 'link';
const MARK_STYLED = 'styled';
const MARK_SUBSCRIPT = 'subscript';
const MARK_SUPERSCRIPT = 'superscript';
const MARK_HIGHLIGHT = 'highlight';
const MARK_TEXT_STYLE = 'textStyle';
const MARK_ANCHOR = 'anchor';
function render(document, options = {}) {
if (typeof document === 'object' && document.type === 'doc' && Array.isArray(document.content)) {
const _options$blokResolver = options.blokResolvers,
blokResolvers = _options$blokResolver === void 0 ? {} : _options$blokResolver,
_options$defaultBlokR = options.defaultBlokResolver,
defaultBlokResolver = _options$defaultBlokR === void 0 ? function () {
return null;
} : _options$defaultBlokR,
_options$nodeResolver = options.nodeResolvers,
customNodeResolvers = _options$nodeResolver === void 0 ? {} : _options$nodeResolver,
_options$markResolver = options.markResolvers,
customMarkResolvers = _options$markResolver === void 0 ? {} : _options$markResolver,
_options$textResolver = options.textResolver,
textResolver = _options$textResolver === void 0 ? function (str) {
return str;
} : _options$textResolver;
const nodeResolvers = _objectSpread2(_objectSpread2({}, defaultNodeResolvers), customNodeResolvers);
const markResolvers = _objectSpread2(_objectSpread2({}, defaultMarkResolvers), customMarkResolvers);
let currentKey = 0;
const addKey = function (element) {
return React.isValidElement(element) ? React.cloneElement(element, {
key: currentKey++
}) : element;
};
const renderNodes = function (nodes) {
const elements = nodes ? nodes.map(renderNode).filter(function (node) {
return node != null;
}) : null;
return Array.isArray(elements) && elements.length === 0 ? null : elements;
};
const renderNode = function (node) {
if (node.type === 'blok') {
const body = node.attrs.body;
return body.map(function (_ref) {
let component = _ref.component,
props = _objectWithoutProperties(_ref, _excluded);
const resolver = blokResolvers[component];
const element = resolver ? resolver(props) : defaultBlokResolver(component, props);
return addKey(element);
});
} else {
var _node$marks;
let childNode;
if (node.type === 'text') {
childNode = textResolver(node.text);
} else {
const resolver = nodeResolvers[node.type];
childNode = resolver ? addKey(resolver(renderNodes(node.content), node.attrs)) : null;
}
const marks = (_node$marks = node.marks) !== null && _node$marks !== void 0 ? _node$marks : [];
return marks.reduceRight(function (children, mark) {
const resolver = markResolvers[mark.type];
return resolver ? addKey(resolver(children, mark.attrs)) : children;
}, childNode);
}
};
return renderNodes(document.content);
} else if (typeof document === 'string') {
const _options$defaultStrin = options.defaultStringResolver,
defaultStringResolver = _options$defaultStrin === void 0 ? function (str) {
return str;
} : _options$defaultStrin,
_options$textResolver2 = options.textResolver,
textResolver = _options$textResolver2 === void 0 ? function (str) {
return str;
} : _options$textResolver2;
return defaultStringResolver(textResolver(document));
}
return null;
}
const simpleNodeResolver = function (element) {
return function (children) {
return children != null ? React.createElement(element, null, children) : null;
};
};
const emptyNodeResolver = function (element) {
return function () {
return React.createElement(element);
};
};
const headingNodeResolver = function (children, props) {
return React.createElement(`h${props.level}`, null, children);
};
const imageNodeResolver = function (children, props) {
return React.createElement('img', props, children);
};
const codeblockNodeResolver = function (children, props) {
const codeProps = {
className: props.class
};
const code = React.createElement('code', codeProps, children);
return React.createElement('pre', null, code);
};
const emojiNodeResolver = function (_, attrs) {
if (!attrs) return null;
const props = {
'data-type': 'emoji',
'data-name': attrs.name,
emoji: attrs.emoji
};
if (attrs.emoji || !attrs.fallbackImage) {
return React.createElement('span', props, attrs.emoji);
} else {
const fallbackProps = {
src: attrs.fallbackImage,
draggable: 'false',
loading: 'lazy',
align: 'absmiddle',
alt: attrs.name
};
const fallback = React.createElement('img', fallbackProps);
return React.createElement('span', props, fallback);
}
};
const tableCellNodeResolver = function (el) {
return function (children, props) {
const tableCellProps = {};
const tableCellStyle = {};
if (props.colspan !== 1) {
tableCellProps.colspan = props.colspan;
}
if (props.rowspan !== 1) {
tableCellProps.rowspan = props.rowspan;
}
if (props.backgroundColor) {
tableCellStyle.backgroundColor = props.backgroundColor;
}
if (Array.isArray(props.colwidth)) {
if (props.colwidth.length === 1) {
tableCellStyle['width'] = props.colwidth[0] + 'px';
} else {
tableCellProps['data-colwidth'] = props.colwidth.join(',');
}
}
if (Object.keys(tableCellStyle).length > 0) {
tableCellProps.style = tableCellStyle;
}
return React.createElement(el, tableCellProps, children);
};
};
const simpleMarkResolver = function (element) {
return function (children) {
return React.createElement(element, null, children);
};
};
const linkMarkResolver = function (children, attrs) {
const props = attrs ? {
href: attrs.linktype === 'email' ? `mailto:${attrs.href}` : attrs.href,
target: attrs.target
} : {};
return React.createElement('a', props, children);
};
const styledMarkResolver = function (children, attrs) {
const props = attrs ? {
className: attrs.class
} : {};
return React.createElement('span', props, children);
};
const highlightMarkResolver = function (children, attrs) {
const props = attrs ? {
style: {
backgroundColor: attrs.color
}
} : {};
return React.createElement('span', props, children);
};
const textStyleMarkResolver = function (children, attrs) {
const props = attrs?.color ? {
style: {
color: attrs.color
}
} : {};
return React.createElement('span', props, children);
};
const anchorMarkResolver = function (children, attrs) {
const props = attrs ? {
id: attrs.id
} : {};
return React.createElement('span', props, children);
};
const defaultNodeResolvers = {
[NODE_HEADING]: headingNodeResolver,
[NODE_CODEBLOCK]: codeblockNodeResolver,
[NODE_IMAGE]: imageNodeResolver,
[NODE_PARAGRAPH]: simpleNodeResolver('p'),
[NODE_QUOTE]: simpleNodeResolver('blockquote'),
[NODE_OL]: simpleNodeResolver('ol'),
[NODE_UL]: simpleNodeResolver('ul'),
[NODE_LI]: simpleNodeResolver('li'),
[NODE_HR]: emptyNodeResolver('hr'),
[NODE_BR]: emptyNodeResolver('br'),
[NODE_EMOJI]: emojiNodeResolver,
[NODE_TABLE]: simpleNodeResolver('table'),
[NODE_TABLE_ROW]: simpleNodeResolver('tr'),
[NODE_TABLE_HEADER]: tableCellNodeResolver('th'),
[NODE_TABLE_CELL]: tableCellNodeResolver('td')
};
const defaultMarkResolvers = {
[MARK_LINK]: linkMarkResolver,
[MARK_STYLED]: styledMarkResolver,
[MARK_BOLD]: simpleMarkResolver('b'),
[MARK_ITALIC]: simpleMarkResolver('i'),
[MARK_STRIKE]: simpleMarkResolver('s'),
[MARK_UNDERLINE]: simpleMarkResolver('u'),
[MARK_CODE]: simpleMarkResolver('code'),
[MARK_SUBSCRIPT]: simpleMarkResolver('sub'),
[MARK_SUPERSCRIPT]: simpleMarkResolver('sup'),
[MARK_HIGHLIGHT]: highlightMarkResolver,
[MARK_TEXT_STYLE]: textStyleMarkResolver,
[MARK_ANCHOR]: anchorMarkResolver
};
export { MARK_ANCHOR, MARK_BOLD, MARK_CODE, MARK_HIGHLIGHT, MARK_ITALIC, MARK_LINK, MARK_STRIKE, MARK_STYLED, MARK_SUBSCRIPT, MARK_SUPERSCRIPT, MARK_TEXT_STYLE, MARK_UNDERLINE, NODE_BR, NODE_CODEBLOCK, NODE_EMOJI, NODE_HEADING, NODE_HR, NODE_IMAGE, NODE_LI, NODE_OL, NODE_PARAGRAPH, NODE_QUOTE, NODE_TABLE, NODE_TABLE_CELL, NODE_TABLE_HEADER, NODE_TABLE_ROW, NODE_UL, render };
//# sourceMappingURL=index.es.js.map