Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/neat-ravens-lick.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@platejs/markdown": patch
---

Serialize new lines (\n) within a paragraph's text node
44 changes: 36 additions & 8 deletions packages/markdown/src/lib/rules/defaultRules.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {
type TListElement,
type TMentionElement,
type TText,
type Descendant,
getPluginKey,
getPluginType,
KEYS,
Expand Down Expand Up @@ -744,20 +745,47 @@ export const defaultRules: MdRules = {
return elements.length === 1 ? elements[0] : elements;
},
serialize: (node, options) => {
let enrichedChildren = node.children;

enrichedChildren = enrichedChildren.map((child) => {
// a child may be split in multiple parts, therefore use flatMap
const enrichedChildren = node.children.flatMap((child) => {
if (child.text === '\n') {
return {
type: 'break',
} as any;
return [
{
type: 'break',
} as Descendant,
];
}

if (child.text === '' && options.preserveEmptyParagraphs !== false) {
return { ...child, text: '\u200B' };
return [{ ...child, text: '\u200B' }];
}

//support linebreaks within a single text node
if (
child.text &&
typeof child.text === 'string' &&
child.text.includes('\n')
) {
const enrichedParts: Descendant[] = [];
const childParts = child.text.split('\n');
childParts.forEach((part, index) => {
if (part.length === 0) {
enrichedParts.push({
type: 'break',
} as Descendant);
} else {
enrichedParts.push({ ...child, text: part });
// do not add line break after the last text that ends this child node (read: paragraph)
if (childParts.length !== index + 1) {
enrichedParts.push({
type: 'break',
} as Descendant);
}
}
});
return enrichedParts;
}

return child;
return [child];
});

const convertedNodes = convertNodesSerialize(
Expand Down
18 changes: 18 additions & 0 deletions packages/markdown/src/lib/serializer/serializeMd.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -254,6 +254,24 @@ describe('serializeMd', () => {
expect(serializeMd(editor as any, { value: slateNodes })).toMatchSnapshot();
});

it('should serialize new lines WITHIN a single text node to line breaks in Markdown', () => {
const slateNodes = [
{
children: [
{
text: 'Text followed by two empty lines\n\n\nFollowed by more text.',
},
],
type: 'p',
},
];

const result = serializeMd(editor as any, { value: slateNodes });
expect(result).toEqual(
`Text followed by two empty lines\\\n\\\n\\\nFollowed by more text.\n`
);
});

it('should serialize lists with spread option correctly', () => {
const listFragment = [
{
Expand Down
Loading
Loading