rich-text-solid-renderer
Version:
contentful rich text renderer for solid js
93 lines (92 loc) • 4.33 kB
JSX
/**
* @ Author: Joel D'Souza
* @ Create Time: 2022-05-17 22:15:07
* @ Modified by: Joel D'Souza
* @ Modified time: 2022-05-20 14:30:30
* @ Description:a clone of https://github.com/contentful/rich-text/tree/master/packages/rich-text-react-renderer
* but for solid-js
* @format
*/
import { For, } from 'solid-js';
import * as O from 'fp-ts/Option';
import { flow, pipe } from 'fp-ts/function';
import { BLOCKS, INLINES, MARKS, isText, } from './type';
const defaultNodeRenderers = {
[BLOCKS.DOCUMENT]: (props) => <>{props.children}</>,
[BLOCKS.PARAGRAPH]: (props) => <p>{props.children}</p>,
[BLOCKS.HEADING_1]: (props) => <h1>{props.children}</h1>,
[BLOCKS.HEADING_2]: (props) => <h2>{props.children}</h2>,
[BLOCKS.HEADING_3]: (props) => <h3>{props.children}</h3>,
[BLOCKS.HEADING_4]: (props) => <h4>{props.children}</h4>,
[BLOCKS.HEADING_5]: (props) => <h5>{props.children}</h5>,
[BLOCKS.HEADING_6]: (props) => <h6>{props.children}</h6>,
[BLOCKS.EMBEDDED_ENTRY]: (props) => <div>{props.children}</div>,
[BLOCKS.UL_LIST]: (props) => <ul>{props.children}</ul>,
[BLOCKS.OL_LIST]: (props) => <ol>{props.children}</ol>,
[BLOCKS.LIST_ITEM]: (props) => <li>{props.children}</li>,
[BLOCKS.QUOTE]: (props) => <blockquote>{props.children}</blockquote>,
[BLOCKS.HR]: () => <hr />,
[BLOCKS.TABLE]: (props) => (<table>
<tbody>{props.children}</tbody>
</table>),
[BLOCKS.TABLE_ROW]: (props) => <tr>{props.children}</tr>,
[BLOCKS.TABLE_HEADER_CELL]: (props) => <th>{props.children}</th>,
[BLOCKS.TABLE_CELL]: (props) => <td>{props.children}</td>,
[INLINES.ASSET_HYPERLINK]: (props) => (<DefaultInline type={INLINES.ASSET_HYPERLINK} node={props.node}/>),
[INLINES.ENTRY_HYPERLINK]: (props) => (<DefaultInline type={INLINES.ENTRY_HYPERLINK} node={props.node}/>),
[INLINES.EMBEDDED_ENTRY]: (props) => (<DefaultInline type={INLINES.EMBEDDED_ENTRY} node={props.node}/>),
[INLINES.HYPERLINK]: (props) => (<a href={props.node.data.uri}>{props.children}</a>),
};
const DefaultInline = (props) => {
return (<span>
type: {props.node.nodeType} id: {props.node.data.target.sys.id}
</span>);
};
const DefaultNode = (props) => {
return <>{props.children}</>;
};
const defaultMarkRenderers = {
[MARKS.BOLD]: (props) => <b>{props.children}</b>,
[MARKS.ITALIC]: (props) => <i>{props.children}</i>,
[MARKS.UNDERLINE]: (props) => <u>{props.children}</u>,
[MARKS.CODE]: (props) => <code>{props.children}</code>,
};
const DefaultMark = (props) => <>{props.children}</>;
const SolidRichText = (props) => {
return (<NodeToSolidComponent node={props.document} options={{
renderNode: {
...defaultNodeRenderers,
...(props.options && props.options.renderNode),
},
renderMark: {
...defaultMarkRenderers,
...(props.options && props.options.renderMark),
},
renderText: props.options && props.options.renderText,
}}/>);
};
const NodeListToSolidComponent = (props) => {
return (<For each={props.nodes}>
{(node) => <NodeToSolidComponent node={node} options={props.options}/>}
</For>);
};
export const NodeToSolidComponent = (props) => {
// for text nodes
if (isText(props.node)) {
return props.node.marks.reduce((v, m) => {
const Value = pipe(props.options, O.fromNullable, O.map(({ renderMark }) => renderMark), O.chain(flow(O.fromNullable, O.map((r) => r[m.type] ?? DefaultMark))), O.getOrElse(() => DefaultMark));
return <Value>{v}</Value>;
}, pipe(props.options, O.fromNullable, O.map(({ renderText }) => renderText), O.chain(flow(O.fromNullable, O.map((r) => {
return r(props.node.value);
}))), O.getOrElse(() => props.node.value)));
}
// for Nodes
const children = (<NodeListToSolidComponent nodes={props.node.content} options={props.options}/>);
const Component = pipe(props.options, O.fromNullable, O.map(({ renderNode }) => renderNode), O.chain(flow(O.fromNullable, O.map((r) => {
return r[props.node.nodeType] ?? DefaultNode;
}))), O.getOrElse(() => DefaultNode));
return (<Component node={props.node}>
{children}
</Component>);
};
export default SolidRichText;