Skip to content

Commit cb73e00

Browse files
authored
Merge pull request #4440 from udecode/claude/issue-4438-20250701_103048
fix(markdown): add spread option to control list spacing
2 parents d2788a7 + b894148 commit cb73e00

File tree

9 files changed

+157
-78
lines changed

9 files changed

+157
-78
lines changed
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
---
2+
"@platejs/markdown": patch
3+
---
4+
5+
Added `spread` option to control list spacing in markdown serialization.
6+
7+
Added a new optional `spread` property to `SerializeMdOptions`:
8+
- When `spread` is `false` (default), lists are rendered compactly
9+
- When `spread` is `true`, lists have double line breaks between items
10+
11+
Before (default):
12+
```markdown
13+
1. Item 1
14+
2. Item 2
15+
```
16+
17+
After (with `spread: true`):
18+
```markdown
19+
1. Item 1
20+
21+
2. Item 2
22+
```

packages/core/CHANGELOG.md

Lines changed: 1 addition & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -6,30 +6,7 @@
66

77
- [#4441](https://github.com/udecode/plate/pull/4441) by [@delijah](https://github.com/delijah) – Expose mimeType to plugin parser functions
88

9-
Added comprehensive copy functionality and view editor support for static rendering.
10-
11-
**New Components:**
12-
13-
- Added `PlateView` component for static editor rendering with copy support
14-
- Added `usePlateViewEditor` hook for creating memoized static editors
15-
16-
**Static Editor Enhancements:**
17-
18-
- Added `withStatic` HOC to enhance editors with static rendering capabilities
19-
- Added `ViewPlugin` that enables copy operations in static editors
20-
- Added `getStaticPlugins` to configure plugins for static rendering
21-
- Added `onCopy` handler that properly serializes content with `x-slate-fragment` format
22-
23-
**New Utilities:**
24-
25-
- Added `getSelectedDomBlocks` to extract selected DOM elements with Slate metadata
26-
- Added `getSelectedDomNode` to get DOM nodes from browser selection
27-
- Added `isSelectOutside` to check if selection is outside editor bounds
28-
- Added `getPlainText` to recursively extract plain text from DOM nodes
29-
30-
This enables seamless copy operations from static Plate editors, allowing content to be pasted into other Slate editors while preserving rich formatting and structure.
31-
32-
- [`a6c3e52`](https://github.com/udecode/plate/commit/a6c3e521c2cd8410d151f0b99a9080bba171b276) by [@felixfeng33](https://github.com/felixfeng33) – Added comprehensive copy functionality and view editor support for static rendering.
9+
- [#4431](https://github.com/udecode/plate/pull/4431) by [@felixfeng33](https://github.com/felixfeng33) – Added comprehensive copy functionality and view editor support for static rendering.
3310

3411
**New Components:**
3512

packages/markdown/src/lib/serializer/__snapshots__/listToMdastTree.spec.ts.snap

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ exports[`listToMdastTree should handle todo lists correctly 1`] = `
3535
},
3636
],
3737
"ordered": false,
38+
"spread": false,
3839
"start": 1,
3940
"type": "list",
4041
}

packages/markdown/src/lib/serializer/listToMdastTree.spec.ts

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ describe('listToMdastTree', () => {
5050
},
5151
],
5252
ordered: false,
53+
spread: false,
5354
start: 1,
5455
type: 'list',
5556
});
@@ -117,6 +118,7 @@ describe('listToMdastTree', () => {
117118
},
118119
],
119120
ordered: false,
121+
spread: false,
120122
start: 1,
121123
type: 'list',
122124
},
@@ -125,6 +127,7 @@ describe('listToMdastTree', () => {
125127
},
126128
],
127129
ordered: false,
130+
spread: false,
128131
start: 1,
129132
type: 'list',
130133
});
@@ -176,6 +179,7 @@ describe('listToMdastTree', () => {
176179
},
177180
],
178181
ordered: true,
182+
spread: false,
179183
start: 1,
180184
type: 'list',
181185
});
@@ -431,4 +435,38 @@ describe('listToMdastTree', () => {
431435

432436
expect(result).toMatchSnapshot();
433437
});
438+
439+
it('should handle spread option correctly', () => {
440+
const nodes = [
441+
{
442+
children: [{ text: 'list1' }],
443+
indent: 1,
444+
listStart: 1,
445+
listStyleType: 'disc',
446+
type: 'p',
447+
},
448+
{
449+
children: [{ text: 'list2' }],
450+
indent: 1,
451+
listStart: 1,
452+
listStyleType: 'disc',
453+
type: 'p',
454+
},
455+
];
456+
457+
// Test with spread: false (default)
458+
const resultNoSpread = listToMdastTree(nodes as any, {
459+
editor,
460+
});
461+
462+
expect(resultNoSpread.spread).toBe(false);
463+
464+
// Test with spread: true
465+
const resultWithSpread = listToMdastTree(nodes as any, {
466+
editor,
467+
spread: true,
468+
});
469+
470+
expect(resultWithSpread.spread).toBe(true);
471+
});
434472
});

packages/markdown/src/lib/serializer/listToMdastTree.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ export function listToMdastTree(
1616
const root: MdList = {
1717
children: [],
1818
ordered: nodes[0].listStyleType === 'decimal',
19+
spread: options.spread ?? false,
1920
start: nodes[0].listStart,
2021
type: 'list',
2122
};
@@ -57,7 +58,12 @@ export function listToMdastTree(
5758
},
5859
],
5960
type: 'listItem',
60-
};
61+
} as any;
62+
63+
// Add spread property to list items when spread is true
64+
if (options.spread) {
65+
(listItem as any).spread = true;
66+
}
6167

6268
// Add checked property for todo lists
6369
if (node.listStyleType === 'todo' && node.checked !== undefined) {
@@ -74,6 +80,7 @@ export function listToMdastTree(
7480
const nestedList: MdList = {
7581
children: [],
7682
ordered: nextNode.listStyleType === 'decimal',
83+
spread: options.spread ?? false,
7784
start: nextNode.listStart,
7885
type: 'list',
7986
};

packages/markdown/src/lib/serializer/serializeMd.spec.ts

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,10 @@ const editor = createTestEditor();
55

66
describe('serializeMd', () => {
77
it('should serialize a simple paragraph', () => {
8-
const result = serializeMd(editor as any, { value: testValue });
8+
const result = serializeMd(editor as any, {
9+
spread: true,
10+
value: testValue,
11+
});
912
expect(result).toMatchSnapshot();
1013
});
1114

@@ -266,4 +269,33 @@ describe('serializeMd', () => {
266269
).toMatchSnapshot();
267270
}
268271
);
272+
273+
it('should serialize lists with spread option correctly', () => {
274+
const listFragment = [
275+
{
276+
children: [{ text: '1' }],
277+
indent: 1,
278+
listStyleType: 'decimal',
279+
type: 'p',
280+
},
281+
{
282+
children: [{ text: '2' }],
283+
indent: 1,
284+
listStart: 2,
285+
listStyleType: 'decimal',
286+
type: 'p',
287+
},
288+
];
289+
290+
// Test with default (spread: false)
291+
const resultDefault = serializeMd(editor as any, { value: listFragment });
292+
expect(resultDefault).toBe('1. 1\n2. 2\n');
293+
294+
// Test with spread: true
295+
const resultWithSpread = serializeMd(editor as any, {
296+
spread: true,
297+
value: listFragment,
298+
});
299+
expect(resultWithSpread).toBe('1. 1\n\n2. 2\n');
300+
});
269301
});

packages/markdown/src/lib/serializer/serializeMd.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ export type SerializeMdOptions = {
1717
preserveEmptyParagraphs?: boolean;
1818
remarkPlugins?: Plugin[];
1919
rules?: MdRules;
20+
spread?: boolean;
2021
value?: Descendant[];
2122
};
2223

packages/markdown/src/lib/serializer/utils/getMergedOptionsSerialize.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ export const getMergedOptionsSerialize = (
3838
editor,
3939
remarkPlugins: options?.remarkPlugins ?? PluginRemarkPlugins ?? [],
4040
rules: mergedRules,
41+
spread: options?.spread,
4142
value: options?.value ?? editor.children,
4243
};
4344
};

0 commit comments

Comments
 (0)