This repository has no description
Something went wrong. Try again.
3.2 kB · 101 lines
TSX
at main
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102// src/components/lexical/Render.tsximport { Fragment, type ReactNode } from 'react'import { Callout } from './Callout'import { LinkPreviewCard } from './LinkPreviewCard'import { PostImage } from './PostImage'import { anchorFor } from '@/lib/lexical-headings'import { mediaUrl } from '@/lib/media-url'
type Node = { type: string; [key: string]: any }
function renderChildren(children: Node[] | undefined): ReactNode { return (children ?? []).map((c, i) => <Fragment key={i}>{renderNode(c)}</Fragment>)}
function renderText(node: Node): ReactNode { let el: ReactNode = node.text const fmt = (node.format as number | undefined) ?? 0 if (fmt & 1) el = <strong>{el}</strong> if (fmt & 2) el = <em>{el}</em> if (fmt & 16) el = <code>{el}</code> return el}
function renderNode(node: Node): ReactNode { switch (node.type) { case 'text': return renderText(node) case 'paragraph': return <p>{renderChildren(node.children)}</p> case 'heading': { const Tag = (node.tag as 'h2' | 'h3' | 'h4' | 'h5' | 'h6') ?? 'h2' const id = anchorFor(node as { children?: Array<{ type: string; text?: string }> }) return <Tag id={id}>{renderChildren(node.children)}</Tag> } case 'list': { const Tag = node.tag === 'ol' ? 'ol' : 'ul' return <Tag>{renderChildren(node.children)}</Tag> } case 'listitem': return <li>{renderChildren(node.children)}</li> case 'quote': return <blockquote>{renderChildren(node.children)}</blockquote> case 'horizontalrule': return <hr /> case 'link': { const fields = node.fields ?? {} const href = fields.url ?? node.url const newTab = fields.newTab ?? false return ( <a href={href} target={newTab ? '_blank' : undefined} rel={newTab ? 'noopener noreferrer' : undefined} > {renderChildren(node.children)} </a> ) } case 'block': { const f = node.fields ?? {} if (f.blockType === 'callout') { return ( <Callout title={f.title} variant={f.variant}> <Render value={f.content} /> </Callout> ) } if (f.blockType === 'linkPreview') { return ( <LinkPreviewCard url={f.url} title={f.title} description={f.description} imageUrl={mediaUrl(f.image)} /> ) } if (f.blockType === 'mediaBlock') { const url = mediaUrl(f.media) if (!url) return null const alt = (typeof f.media === 'object' && f.media?.alt) || f.caption || '' return <PostImage src={url} alt={alt} caption={f.caption} widthHint={f.widthHint} /> } if (f.blockType === 'Code') { return ( <pre> <code className={f.language ? `language-${f.language}` : undefined}>{f.code}</code> </pre> ) } return null } default: return null }}
export function Render({ value }: { value?: { root: { children: Node[] } } | null }) { if (!value?.root?.children) return null return <>{renderChildren(value.root.children as Node[])}</>}