Created
February 16, 2021 07:52
-
-
Save dimaip/0454b58d360f26c1e6a87310ace61f8c to your computer and use it in GitHub Desktop.
Keystone SlateJS v0.47 sample rendering
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 React, { useContext } from 'react' | |
interface Mark { | |
type: string | |
} | |
export interface ElementNode { | |
type: string | |
nodes: Array<ElementNode | LeafNode> | |
data: { | |
[item: string]: string | |
} | |
} | |
export interface LeafNode { | |
type: string | |
text: string | |
marks: Mark[] | |
} | |
interface RenderElementArgs { | |
nodes: JSX.Element | |
element: ElementNode | |
} | |
interface RenderLeafArgs { | |
nodes: JSX.Element | |
leaf: LeafNode | |
} | |
interface SlatePresentationContextType { | |
renderElement: (props: RenderElementArgs) => JSX.Element | |
renderLeaf: (props: RenderLeafArgs) => JSX.Element | |
} | |
const SlatePresentationContext = React.createContext<SlatePresentationContextType>({ | |
renderElement: (props: RenderElementArgs) => <DefaultElement {...props} />, | |
renderLeaf: (props: RenderLeafArgs) => <DefaultLeaf {...props} />, | |
}) | |
const useSlatePresentation = (): SlatePresentationContextType => | |
useContext<SlatePresentationContextType>(SlatePresentationContext) | |
const isElement = (value: ElementNode | LeafNode): value is ElementNode => | |
value instanceof Object && 'nodes' in value && Array.isArray(value.nodes) | |
function Element({ element }: { element: ElementNode }): JSX.Element { | |
const { renderElement } = useSlatePresentation() | |
return <>{renderElement({ nodes: <Children nodes={element.nodes} />, element })}</> | |
} | |
function Leaf({ leaf }: { leaf: LeafNode }): JSX.Element { | |
const { renderLeaf } = useSlatePresentation() | |
return <>{renderLeaf({ nodes: <span>{leaf.text}</span>, leaf })}</> | |
} | |
function Children({ nodes = [] }: { nodes: Array<ElementNode | LeafNode> }): JSX.Element { | |
return ( | |
<> | |
{nodes.map((child, i) => { | |
if (isElement(child)) { | |
return <Element key={i} element={child} /> | |
} else { | |
return <Leaf key={i} leaf={child} /> | |
} | |
})} | |
</> | |
) | |
} | |
export function SlateReactPresentation({ | |
nodes = [], | |
renderElement = (props) => <DefaultElement {...props} />, | |
renderLeaf = (props) => <DefaultLeaf {...props} />, | |
}: { | |
nodes: Array<ElementNode | LeafNode> | |
renderElement: (props: RenderElementArgs) => JSX.Element | |
renderLeaf: (props: RenderLeafArgs) => JSX.Element | |
}): JSX.Element { | |
return ( | |
<SlatePresentationContext.Provider value={{ renderElement, renderLeaf }}> | |
<Children nodes={nodes} /> | |
</SlatePresentationContext.Provider> | |
) | |
} | |
function DefaultElement({ nodes, element }: RenderElementArgs): JSX.Element { | |
return <div>{nodes}</div> | |
} | |
function DefaultLeaf({ nodes, leaf }: RenderLeafArgs): JSX.Element { | |
return <span>{nodes}</span> | |
} |
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
<SlateReactPresentation | |
nodes={nodes} | |
renderElement={(props) => { | |
const { element, nodes } = props | |
switch (element.type) { | |
case 'heading': | |
return <Typography variant="h3">{nodes}</Typography> | |
case 'paragraph': | |
return <Typography variant="body1">{nodes}</Typography> | |
case 'blockquote': | |
return ( | |
<blockquote | |
css={(theme: Theme) => css` | |
border-left: 4px solid ${theme.palette.divider}; | |
margin-left: 0; | |
padding-left: ${theme.spacing(2)}px; | |
`} | |
> | |
<Typography variant="body1">{nodes}</Typography> | |
</blockquote> | |
) | |
case 'list-item': | |
return ( | |
<li | |
css={(theme: Theme) => | |
css` | |
margin-left: ${theme.spacing(4)}px; | |
` | |
} | |
> | |
{nodes} | |
</li> | |
) | |
case 'unordered-list': | |
return ( | |
<Typography variant="body1"> | |
<ul | |
css={css` | |
list-style-type: circle; | |
& > li { | |
list-style-type: circle; | |
} | |
`} | |
> | |
{nodes} | |
</ul> | |
</Typography> | |
) | |
case 'ordered-list': | |
return ( | |
<Typography variant="body1"> | |
<ol | |
css={css` | |
list-style-type: decimal; | |
& > li { | |
list-style-type: decimal; | |
} | |
`} | |
> | |
{nodes} | |
</ol> | |
</Typography> | |
) | |
case 'link': | |
return ( | |
<Link href={element.data?.href} passHref> | |
<a>{nodes}</a> | |
</Link> | |
) | |
default: | |
return <div>{nodes}</div> | |
} | |
}} | |
renderLeaf={(props) => { | |
const { leaf } = props | |
let result = <>{leaf.text}</> | |
leaf.marks.forEach((mark) => { | |
switch (mark.type) { | |
case 'bold': | |
result = <strong>{result}</strong> | |
break | |
case 'italic': | |
result = <em>{result}</em> | |
break | |
case 'underline': | |
result = <u>{result}</u> | |
break | |
case 'strikethrough': | |
result = <s>{result}</s> | |
break | |
default: | |
result = <span>{result}</span> | |
} | |
}) | |
return result | |
}} | |
/> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment