diff --git a/src/examples/nested-jsx-elements.tsx b/src/examples/nested-jsx-elements.tsx new file mode 100644 index 00000000..8836173c --- /dev/null +++ b/src/examples/nested-jsx-elements.tsx @@ -0,0 +1,116 @@ +import React from 'react' +import { MdxJsxTextElement } from 'mdast-util-mdx' +import { + Button, + DiffSourceToggleWrapper, + JsxComponentDescriptor, + MDXEditor, + NestedLexicalEditor, + UndoRedo, + diffSourcePlugin, + jsxPlugin, + jsxPluginHooks, + toolbarPlugin +} from '../' +const jsxMarkdown = ` + Content *foo*more Content + ` +const jsxComponentDescriptors: JsxComponentDescriptor[] = [ + { + name: 'Card', + kind: 'text', + source: './external', + props: [], + hasChildren: true, + Editor: () => { + return + } + }, + { + name: 'Grid', + kind: 'flow', + source: './external', + props: [], + hasChildren: true, + Editor: () => { + return ( +
+ + block + getContent={(node) => node.children} + // eslint-disable-next-line @typescript-eslint/no-explicit-any + getUpdatedMdastNode={(mdastNode, children: any) => { + return { + ...mdastNode, + // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment + children + } + }} + /> +
+ ) + } + } +] + +const InsertCard = () => { + const insertJsx = jsxPluginHooks.usePublisher('insertJsx') + return ( + <> + + + ) +} + +const InsertGrid = () => { + const insertJsx = jsxPluginHooks.usePublisher('insertJsx') + return ( + <> + + + ) +} + +export const Example = () => { + return ( + ( + <> + + + + + + + ) + }) + ]} + /> + ) +} diff --git a/src/exportMarkdownFromLexical.ts b/src/exportMarkdownFromLexical.ts index d8517dce..b4ba555b 100644 --- a/src/exportMarkdownFromLexical.ts +++ b/src/exportMarkdownFromLexical.ts @@ -103,6 +103,7 @@ export interface ExportLexicalTreeOptions { visitors: LexicalVisitor[] jsxComponentDescriptors: JsxComponentDescriptor[] jsxIsAvailable: boolean + addImportStatements?: boolean } function isParent(node: unknown): node is Mdast.Parent { @@ -116,7 +117,8 @@ export function exportLexicalTreeToMdast({ root, visitors, jsxComponentDescriptors, - jsxIsAvailable + jsxIsAvailable, + addImportStatements = true }: ExportLexicalTreeOptions): Mdast.Root { let unistRoot: Mdast.Root | null = null const referredComponents = new Set() @@ -240,10 +242,12 @@ export function exportLexicalTreeToMdast({ const frontmatter = typedRoot.children.find((child) => child.type === 'yaml') - if (frontmatter) { - typedRoot.children.splice(typedRoot.children.indexOf(frontmatter) + 1, 0, ...imports) - } else { - typedRoot.children.unshift(...imports) + if (addImportStatements) { + if (frontmatter) { + typedRoot.children.splice(typedRoot.children.indexOf(frontmatter) + 1, 0, ...imports) + } else { + typedRoot.children.unshift(...imports) + } } fixWrappingWhitespace(typedRoot, []) @@ -257,7 +261,7 @@ export function exportLexicalTreeToMdast({ } function collapseNestedHtmlTags(node: Mdast.Parent | Mdast.Content) { - if ('children' in node) { + if ('children' in node && node.children) { if (isMdastHTMLNode(node) && node.children.length === 1) { const onlyChild = node.children[0] if (onlyChild.type === 'mdxJsxTextElement' && onlyChild.name === 'span') { @@ -339,7 +343,7 @@ function fixWrappingWhitespace(node: Mdast.Parent | Mdast.Content, parentChain: } } } - if (Object.hasOwn(node, 'children')) { + if ('children' in node && node.children) { const nodeAsParent = node as Mdast.Parent nodeAsParent.children.forEach((child) => fixWrappingWhitespace(child, [...parentChain, nodeAsParent])) } diff --git a/src/plugins/core/LexicalTextVisitor.ts b/src/plugins/core/LexicalTextVisitor.ts index c01b00d3..2dcba76d 100644 --- a/src/plugins/core/LexicalTextVisitor.ts +++ b/src/plugins/core/LexicalTextVisitor.ts @@ -8,13 +8,19 @@ export function isMdastText(mdastNode: Mdast.Content): mdastNode is Mdast.Text { return mdastNode.type === 'text' } +const JOINABLE_TAGS = ['u', 'span'] + export const LexicalTextVisitor: LexicalExportVisitor = { shouldJoin: (prevNode, currentNode) => { if (['text', 'emphasis', 'strong'].includes(prevNode.type)) { return prevNode.type === currentNode.type } - if (prevNode.type === 'mdxJsxTextElement' && (currentNode as unknown as MdxJsxTextElement).type === 'mdxJsxTextElement') { + if ( + prevNode.type === 'mdxJsxTextElement' && + (currentNode as unknown as MdxJsxTextElement).type === 'mdxJsxTextElement' && + JOINABLE_TAGS.includes((currentNode as unknown as MdxJsxTextElement).name as string) + ) { const currentMdxNode: MdxJsxTextElement = currentNode as unknown as MdxJsxTextElement return prevNode.name === currentMdxNode.name && JSON.stringify(prevNode.attributes) === JSON.stringify(currentMdxNode.attributes) } diff --git a/src/plugins/core/NestedLexicalEditor.tsx b/src/plugins/core/NestedLexicalEditor.tsx index 089f170f..9b7eb573 100644 --- a/src/plugins/core/NestedLexicalEditor.tsx +++ b/src/plugins/core/NestedLexicalEditor.tsx @@ -86,14 +86,18 @@ export function useMdastNodeUpdater() { const { parentEditor, mdastNode, lexicalNode } = useNestedEditorContext() return function updateMdastNode(node: Partial) { - parentEditor.update(() => { - $addUpdateTag('history-push') - const currentNode = $getNodeByKey(lexicalNode.getKey()) - if (currentNode) { - // eslint-disable-next-line @typescript-eslint/no-unsafe-call - currentNode.setMdastNode({ ...mdastNode, ...node }) - } - }) + parentEditor.update( + () => { + $addUpdateTag('history-push') + const currentNode = $getNodeByKey(lexicalNode.getKey()) + if (currentNode) { + // eslint-disable-next-line @typescript-eslint/no-unsafe-call + currentNode.setMdastNode({ ...mdastNode, ...node }) + } + }, + { discrete: true } + ) + parentEditor.dispatchCommand(NESTED_EDITOR_UPDATED_COMMAND, undefined) } } @@ -219,7 +223,8 @@ export const NestedLexicalEditor = function (props: Nes root: $getRoot(), visitors: exportVisitors, jsxComponentDescriptors, - jsxIsAvailable + jsxIsAvailable, + addImportStatements: false }) const content: Mdast.Content[] = block ? mdast.children : (mdast.children[0] as Mdast.Paragraph)!.children updateMdastNode(getUpdatedMdastNode(structuredClone(mdastNode) as any, content as any)) diff --git a/src/plugins/core/index.ts b/src/plugins/core/index.ts index e06b8cac..5fd162f4 100644 --- a/src/plugins/core/index.ts +++ b/src/plugins/core/index.ts @@ -452,6 +452,10 @@ export const coreSystem = system((r) => { setTimeout(() => node.select()) } }) + + setTimeout(() => { + theEditor.dispatchCommand(NESTED_EDITOR_UPDATED_COMMAND, undefined) + }) } } })