'use client' import { Fragment } from 'react' import type { SerializedInlineImageNode, SerializedTextNode } from '@byline/richtext-lexical' import { Table } from '@byline/ui/react' import { AdmonitionSerializer } from '../../admonition/index.tsx' import { CodeSerializer } from '../../code/code-serializer.tsx' import { HeadingWithAnchorSerializer } from '../../heading-anchor/index.ts' import { InlineImageSerializer } from '../../inline-image/index.tsx' import { LayoutContainerSerializer, LayoutItemSerializer } from '../../layout/index.tsx' import { LinkLexicalSerializer } from '../../link/link-lexical.tsx' import { ListItemSerializer, ListSerializer } from '../../list/index.ts' import { TableCellSerializer } from '../../table-cell/index.tsx' import { VimeoSerializer } from '../../vimeo/index.tsx' import { YouTubeSerializer } from '../../youtube/index.tsx' import { IS_BOLD, IS_CODE, IS_ITALIC, IS_STRIKETHROUGH, IS_SUBSCRIPT, IS_SUPERSCRIPT, IS_UNDERLINE, } from './richtext-node-formats.ts' import type { Locale } from '@/ui/byline/types/i18n' import type { SerializedLexicalNode } from './types.ts' export interface SerializeOptions { renderParagraphInline: boolean disableAnimation?: boolean } export interface SerializeProps { nodes: SerializedLexicalNode[] lng: Locale options?: SerializeOptions } export function Serialize({ nodes, lng, options = { renderParagraphInline: false }, }: SerializeProps): React.JSX.Element { return ( {nodes?.map((node, index): React.JSX.Element | null => { if (node.type === 'text') { const textNode = node as SerializedTextNode const { text, format } = textNode if (format & IS_BOLD) { return {text} } if (format & IS_ITALIC) { return {text} } if (format & IS_STRIKETHROUGH) { return ( {text} ) } if (format & IS_UNDERLINE) { return ( {text} ) } if (format & IS_CODE) { return {text} } if (format & IS_SUBSCRIPT) { return {text} } if (format & IS_SUPERSCRIPT) { return {text} } return {text} } if (node == null) { return null } // NOTE: Hacky fix for // https://github.com/facebook/lexical/blob/d10c4e6e55261b2fdd7d1845aed46151d0f06a8c/packages/lexical-list/src/LexicalListItemNode.ts#L133 // which does not return checked: false (only true - i.e. there is no prop for false) // NOTE: also 'look ahead' for table rows that should be a header. const serializedChildrenFn = (node: SerializedLexicalNode): React.JSX.Element | null => { if (node.children == null) { return null } else { if (node?.type === 'list' && node?.listType === 'check') { for (const item of node.children) { if (!item?.checked) { item.checked = false } } return Serialize({ nodes: node.children, lng, options }) } else { return Serialize({ nodes: node.children, lng, options }) } } } const serializedChildren = serializedChildrenFn(node) switch (node.type) { case 'linebreak': { return
} case 'quote': { return
{serializedChildren}
} case 'horizontalrule': { return (
) } case 'paragraph': { if (options.renderParagraphInline) { return {serializedChildren} } else { return

{serializedChildren}

} } case 'heading': { return } case 'list': { return ( {serializedChildren} ) } case 'listitem': { return ( {serializedChildren} ) } case 'link': { return ( {serializedChildren} ) } case 'admonition': { return ( ) } case 'inline-image': { return ( ) } case 'code': { return } case 'table': { return ( {serializedChildren}
) } case 'tablerow': { return {serializedChildren} } case 'tablecell': { // TODO: revisit - we special case inline images if they appear inside a table // cell - and so that's why we're using the TableCellSerializer now return ( ) // if (node?.headerState === 1 || node?.headerState === 2 || node?.headerState === 3) { // return {serializedChildren} // } else { // return {serializedChildren} // } } case 'layout-container': { return ( ) } case 'layout-item': { return ( ) } case 'youtube': { return } case 'vimeo': { return } // case 'code-highlight': { // return {`${node.text}\r\n`} // } default: return null } })}
) }