Skip to content

Instantly share code, notes, and snippets.

@storybynumbers
Last active December 14, 2018 10:56
Show Gist options
  • Save storybynumbers/c91ec491e323c999edba244304d795fe to your computer and use it in GitHub Desktop.
Save storybynumbers/c91ec491e323c999edba244304d795fe to your computer and use it in GitHub Desktop.
render contentful rich text as react components
import {
BLOCKS,
MARKS,
INLINES,
helpers
} from '@contentful/rich-text-types';
const defaultInline = (type, node, key) => {
return <span key={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}</span>
}
const defaultMarkRenderers = {
[MARKS.BOLD]: (text, key) => <strong key={key}>{text}</strong>,
[MARKS.ITALIC]: (text, key) => <em key={key}>{text}</em>,
[MARKS.UNDERLINE]: (text, key) => <u key={key}>{text}</u>,
[MARKS.CODE]: (text, key) => <code key={key}>{text}</code>,
};
const defaultNodeRenderers = {
[BLOCKS.PARAGRAPH]: (node, key, next) => <p key={key}>{next(node.content, key, next)}</p>,
[BLOCKS.HEADING_1]: (node, key, next) => <h1 key={key}>{next(node.content, key, next)}</h1>,
[BLOCKS.HEADING_2]: (node, key, next) => <h2 key={key}>{next(node.content, key, next)}</h2>,
[BLOCKS.HEADING_3]: (node, key, next) => <h3 key={key}>{next(node.content, key, next)}</h3>,
[BLOCKS.HEADING_4]: (node, key, next) => <h4 key={key}>{next(node.content, key, next)}</h4>,
[BLOCKS.HEADING_5]: (node, key, next) => <h5 key={key}>{next(node.content, key, next)}</h5>,
[BLOCKS.HEADING_6]: (node, key, next) => <h6 key={key}>{next(node.content, key, next)}</h6>,
[BLOCKS.EMBEDDED_ENTRY]: (node, key, next) => <div key={key}>{next(node.content, key, next)}</div>,
[BLOCKS.UL_LIST]: (node, key, next) => <ul key={key}>{next(node.content, key, next)}</ul>,
[BLOCKS.OL_LIST]: (node, key, next) => <ol key={key}>{next(node.content, key, next)}</ol>,
[BLOCKS.LIST_ITEM]: (node, key, next) => <li key={key}>{next(node.content, key, next)}</li>,
[BLOCKS.QUOTE]: (node, key, next) => <blockquote key={key}>{next(node.content, key, next)}</blockquote>,
[BLOCKS.HR]: (node, key) => <hr key={key} />,
[INLINES.ASSET_HYPERLINK]: (node, key) => defaultInline(INLINES.ASSET_HYPERLINK, node, key),
[INLINES.ENTRY_HYPERLINK]: (node, key) => defaultInline(INLINES.ENTRY_HYPERLINK, node, key),
[INLINES.EMBEDDED_ENTRY]: (node, key) => defaultInline(INLINES.EMBEDDED_ENTRY, node, key),
[INLINES.HYPERLINK]: (node, key, next) => {
return (<a href={node.data.uri} key={key}>{next(node.content, key, next)}</a>)
},
text: ({ marks, value }, key, markRenderer) => {
return marks.length ? (
marks.reduce((aggregate, mark, i) => markRenderer[mark.type](aggregate, `${key}-${i}`), value)
) : value;
},
};
const renderNodeList = (nodes, key, next) => {
return nodes.map((node, i) => renderNode(node, `${key}-${i}`, next))
};
const renderNode = (node, key, next) => {
const nodeRenderer = next.node;
console.log(key, nodeRenderer ? 'yes' : 'no', next);
//return 'temp';
if (helpers.isText(node)) {
// We're at final tip of node branch, can render text.
const markerRender = next.mark;
return nodeRenderer.text(node, key, markerRender)
} else {
const nextNode = nodes => renderNodeList(nodes, key, next);
if (!nodeRenderer) {
return <div>{`${key} ;lost nodeRenderer`}</div>
}
if (!node.nodeType || !nodeRenderer[node.nodeType]) {
// TODO: Figure what to return when passed an unrecognized node.
console.log('unrecognized node', node)
return '';
}
return nodeRenderer[node.nodeType](node, key, nextNode);
}
};
const RichText = ({ document, options = {} }) => {
// console.log(options)
const renderer = {
node: {
...defaultNodeRenderers,
...options.renderNode,
},
mark: {
...defaultMarkRenderers,
...options.renderMark,
},
};
return renderNodeList(document.content, 'RichText-', renderer)
}
export default RichText
@storybynumbers
Copy link
Author

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment