Last active
December 14, 2018 10:56
-
-
Save storybynumbers/c91ec491e323c999edba244304d795fe to your computer and use it in GitHub Desktop.
render contentful rich text as react components
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Moving this to repo: https://github.com/storybynumbers/rich-text-to-react