From dbebfece1e3bc1c12fe2f1d00bfe0b5b78d61094 Mon Sep 17 00:00:00 2001 From: Na'aman Hirschfeld Date: Sat, 21 Dec 2024 12:21:16 +0100 Subject: [PATCH 1/3] chore: updated handling of markdown headers --- .../deserializer/utils/deserializeMd.spec.tsx | 80 ++++++++++++++++--- .../remark-slate/remarkDefaultElementRules.ts | 17 +++- .../remarkTransformElementChildren.ts | 4 +- 3 files changed, 85 insertions(+), 16 deletions(-) diff --git a/packages/markdown/src/lib/deserializer/utils/deserializeMd.spec.tsx b/packages/markdown/src/lib/deserializer/utils/deserializeMd.spec.tsx index 9716518543..66f2ba8941 100644 --- a/packages/markdown/src/lib/deserializer/utils/deserializeMd.spec.tsx +++ b/packages/markdown/src/lib/deserializer/utils/deserializeMd.spec.tsx @@ -341,11 +341,29 @@ describe('deserializeMd', () => { expect(deserializeMd(editor, input)).toEqual(output); }); - it('should deserialize headings', () => { - const input = Array.from( - { length: 6 }, - (_, i) => `${'#'.repeat(i + 1)} Heading ${i + 1}` - ).join('\n\n'); + it('should deserialize line break tags', () => { + const input = 'Line 1
Line 2'; + + const output = ( + + + Line 1 + {'\n'} + Line 2 + + + ); + + expect(deserializeMd(editor, input)).toEqual(output); + }); + + it('should deserialize all heading levels (h1-h6)', () => { + const input = `# Heading 1 +## Heading 2 +### Heading 3 +#### Heading 4 +##### Heading 5 +###### Heading 6`; const output = ( @@ -361,16 +379,54 @@ describe('deserializeMd', () => { expect(deserializeMd(editor, input)).toEqual(output); }); - it('should deserialize line break tags', () => { - const input = 'Line 1
Line 2'; + it('should handle headings with multiple spaces', () => { + const input = `# Heading 1 +## Heading 2 +### Heading 3 `; const output = ( - - Line 1 - {'\n'} - Line 2 - + Heading 1 + Heading 2 + Heading 3 + + ); + + expect(deserializeMd(editor, input)).toEqual(output); + }); + + it('should handle more than 6 hashes as h6', () => { + const input = `####### Should be h6`; + + const output = ( + + Should be h6 + + ); + + expect(deserializeMd(editor, input)).toEqual(output); + }); + + it('should handle headings with no space after hash', () => { + const input = `#No space`; + + const output = ( + + #No space + + ); + + expect(deserializeMd(editor, input)).toEqual(output); + }); + + it('should handle escaped hashes', () => { + const input = `\\# Not a heading +\\## Also not a heading`; + + const output = ( + + # Not a heading + ## Also not a heading ); diff --git a/packages/markdown/src/lib/remark-slate/remarkDefaultElementRules.ts b/packages/markdown/src/lib/remark-slate/remarkDefaultElementRules.ts index 21eac86b12..3d96570776 100644 --- a/packages/markdown/src/lib/remark-slate/remarkDefaultElementRules.ts +++ b/packages/markdown/src/lib/remark-slate/remarkDefaultElementRules.ts @@ -39,6 +39,8 @@ export const remarkDefaultElementRules: RemarkElementRules = { }, heading: { transform: (node, options) => { + const depth = Math.max(1, Math.min(6, node.depth ?? 1)); + const headingType = { 1: 'h1', 2: 'h2', @@ -46,11 +48,22 @@ export const remarkDefaultElementRules: RemarkElementRules = { 4: 'h4', 5: 'h5', 6: 'h6', - }[node.depth ?? 1]; + }[depth]; + + const type = options.editor.getType({ key: headingType }); + + if (!type) { + console.warn(`Heading type ${headingType} not registered in editor`); + + return { + children: remarkTransformElementChildren(node, options), + type: options.editor.getType({ key: 'p' }), + }; + } return { children: remarkTransformElementChildren(node, options), - type: options.editor.getType({ key: headingType }), + type: type, }; }, }, diff --git a/packages/markdown/src/lib/remark-slate/remarkTransformElementChildren.ts b/packages/markdown/src/lib/remark-slate/remarkTransformElementChildren.ts index fd4fa7c936..886d17185b 100644 --- a/packages/markdown/src/lib/remark-slate/remarkTransformElementChildren.ts +++ b/packages/markdown/src/lib/remark-slate/remarkTransformElementChildren.ts @@ -8,9 +8,9 @@ export const remarkTransformElementChildren = ( node: MdastNode, options: RemarkPluginOptions ): TDescendant[] => { - const { children } = node; + const { children = [] } = node; - if (!children || children.length === 0) { + if (children.length === 0) { return [{ text: '' }]; } From a79739ed5e94b6470919e6b207aa21043d8cbf4c Mon Sep 17 00:00:00 2001 From: Na'aman Hirschfeld Date: Sat, 21 Dec 2024 14:01:31 +0100 Subject: [PATCH 2/3] Update packages/markdown/src/lib/remark-slate/remarkDefaultElementRules.ts --- .../markdown/src/lib/remark-slate/remarkDefaultElementRules.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/markdown/src/lib/remark-slate/remarkDefaultElementRules.ts b/packages/markdown/src/lib/remark-slate/remarkDefaultElementRules.ts index 3d96570776..398797e106 100644 --- a/packages/markdown/src/lib/remark-slate/remarkDefaultElementRules.ts +++ b/packages/markdown/src/lib/remark-slate/remarkDefaultElementRules.ts @@ -53,7 +53,6 @@ export const remarkDefaultElementRules: RemarkElementRules = { const type = options.editor.getType({ key: headingType }); if (!type) { - console.warn(`Heading type ${headingType} not registered in editor`); return { children: remarkTransformElementChildren(node, options), From 82c54ce0c175720c2d85451baaf52419ddbf10f0 Mon Sep 17 00:00:00 2001 From: Na'aman Hirschfeld Date: Sat, 21 Dec 2024 14:15:45 +0100 Subject: [PATCH 3/3] chore: fix typing issue --- packages/markdown/src/lib/MarkdownPlugin.ts | 2 +- .../src/lib/remark-slate/remarkDefaultElementRules.ts | 10 +--------- 2 files changed, 2 insertions(+), 10 deletions(-) diff --git a/packages/markdown/src/lib/MarkdownPlugin.ts b/packages/markdown/src/lib/MarkdownPlugin.ts index 1e9ff29e44..872251154b 100644 --- a/packages/markdown/src/lib/MarkdownPlugin.ts +++ b/packages/markdown/src/lib/MarkdownPlugin.ts @@ -63,7 +63,7 @@ export const MarkdownPlugin = createTSlatePlugin({ .extend(({ api }) => ({ parser: { deserialize: ({ data }) => api.markdown.deserialize(data), - format: 'text/plain', + format: 'text/markdown', query: ({ data, dataTransfer }) => { const htmlData = dataTransfer.getData('text/html'); diff --git a/packages/markdown/src/lib/remark-slate/remarkDefaultElementRules.ts b/packages/markdown/src/lib/remark-slate/remarkDefaultElementRules.ts index 398797e106..f8a43d757a 100644 --- a/packages/markdown/src/lib/remark-slate/remarkDefaultElementRules.ts +++ b/packages/markdown/src/lib/remark-slate/remarkDefaultElementRules.ts @@ -50,15 +50,7 @@ export const remarkDefaultElementRules: RemarkElementRules = { 6: 'h6', }[depth]; - const type = options.editor.getType({ key: headingType }); - - if (!type) { - - return { - children: remarkTransformElementChildren(node, options), - type: options.editor.getType({ key: 'p' }), - }; - } + const type = options.editor.getType({ key: headingType ?? 'h3' }); return { children: remarkTransformElementChildren(node, options),