fix(editor): merge adjacent text nodes with same marks (#3173)
This commit is contained in:
parent
0d7e36ba79
commit
b4c5fc7783
@ -1,4 +1,4 @@
|
||||
import { wrapInlinesWithTexts } from '../remarkSlate';
|
||||
import { wrapInlinesWithTexts, mergeAdjacentTexts } from '../remarkSlate';
|
||||
describe('remarkSlate', () => {
|
||||
describe('wrapInlinesWithTexts', () => {
|
||||
it('should handle empty array', () => {
|
||||
@ -74,4 +74,72 @@ describe('remarkSlate', () => {
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('mergeAdjacentTexts', () => {
|
||||
it('should handle empty array', () => {
|
||||
const children = [];
|
||||
expect(mergeAdjacentTexts(children)).toBe(children);
|
||||
});
|
||||
|
||||
it('should merge adjacent texts with same marks', () => {
|
||||
const children = [
|
||||
{ object: 'text', text: '<a href="https://www.netlify.com" target="_blank">', marks: [] },
|
||||
{ object: 'text', text: 'Netlify', marks: [] },
|
||||
{ object: 'text', text: '</a>', marks: [] },
|
||||
];
|
||||
|
||||
expect(mergeAdjacentTexts(children)).toEqual([
|
||||
{
|
||||
object: 'text',
|
||||
text: '<a href="https://www.netlify.com" target="_blank">Netlify</a>',
|
||||
marks: [],
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
it('should not merge adjacent texts with different marks', () => {
|
||||
const children = [
|
||||
{ object: 'text', text: '<a href="https://www.netlify.com" target="_blank">', marks: [] },
|
||||
{ object: 'text', text: 'Netlify', marks: ['b'] },
|
||||
{ object: 'text', text: '</a>', marks: [] },
|
||||
];
|
||||
|
||||
expect(mergeAdjacentTexts(children)).toEqual(children);
|
||||
});
|
||||
|
||||
it('should handle mixed children array', () => {
|
||||
const children = [
|
||||
{ object: 'inline' },
|
||||
{ object: 'text', text: '<a href="https://www.netlify.com" target="_blank">', marks: [] },
|
||||
{ object: 'text', text: 'Netlify', marks: [] },
|
||||
{ object: 'text', text: '</a>', marks: [] },
|
||||
{ object: 'inline' },
|
||||
{ object: 'text', text: '<a href="https://www.netlify.com" target="_blank">', marks: [] },
|
||||
{ object: 'text', text: 'Netlify', marks: ['b'] },
|
||||
{ object: 'text', text: '</a>', marks: [] },
|
||||
{ object: 'text', text: '<a href="https://www.netlify.com" target="_blank">', marks: [] },
|
||||
{ object: 'inline' },
|
||||
{ object: 'text', text: '</a>', marks: [] },
|
||||
];
|
||||
|
||||
expect(mergeAdjacentTexts(children)).toEqual([
|
||||
{ object: 'inline' },
|
||||
{
|
||||
object: 'text',
|
||||
text: '<a href="https://www.netlify.com" target="_blank">Netlify</a>',
|
||||
marks: [],
|
||||
},
|
||||
{ object: 'inline' },
|
||||
{ object: 'text', text: '<a href="https://www.netlify.com" target="_blank">', marks: [] },
|
||||
{ object: 'text', text: 'Netlify', marks: ['b'] },
|
||||
{
|
||||
object: 'text',
|
||||
text: '</a><a href="https://www.netlify.com" target="_blank">',
|
||||
marks: [],
|
||||
},
|
||||
{ object: 'inline' },
|
||||
{ object: 'text', text: '</a>', marks: [] },
|
||||
]);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { isEmpty, isArray, flatMap, map, flatten } from 'lodash';
|
||||
import { isEmpty, isArray, flatMap, map, flatten, isEqual } from 'lodash';
|
||||
|
||||
/**
|
||||
* Map of MDAST node types to Slate node types.
|
||||
@ -30,6 +30,7 @@ const markMap = {
|
||||
|
||||
const isInline = node => node.object === 'inline';
|
||||
const isText = node => node.object === 'text';
|
||||
const isMarksEqual = (node1, node2) => isEqual(node1.marks, node2.marks);
|
||||
|
||||
export const wrapInlinesWithTexts = children => {
|
||||
if (children.length <= 0) {
|
||||
@ -64,6 +65,39 @@ export const wrapInlinesWithTexts = children => {
|
||||
return children;
|
||||
};
|
||||
|
||||
export const mergeAdjacentTexts = children => {
|
||||
if (children.length <= 0) {
|
||||
return children;
|
||||
}
|
||||
|
||||
const mergedChildren = [];
|
||||
|
||||
let isMerging = false;
|
||||
let current;
|
||||
|
||||
for (let i = 0; i < children.length - 1; i++) {
|
||||
if (!isMerging) {
|
||||
current = children[i];
|
||||
}
|
||||
const next = children[i + 1];
|
||||
if (isText(current) && isText(next) && isMarksEqual(current, next)) {
|
||||
isMerging = true;
|
||||
current = { ...current, text: `${current.text}${next.text}` };
|
||||
} else {
|
||||
mergedChildren.push(current);
|
||||
isMerging = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (isMerging) {
|
||||
mergedChildren.push(current);
|
||||
} else {
|
||||
mergedChildren.push(children[children.length - 1]);
|
||||
}
|
||||
|
||||
return mergedChildren;
|
||||
};
|
||||
|
||||
/**
|
||||
* A Remark plugin for converting an MDAST to Slate Raw AST. Remark plugins
|
||||
* return a `transformNode` function that receives the MDAST as it's first argument.
|
||||
@ -87,6 +121,8 @@ export default function remarkToSlate({ voidCodeBlock } = {}) {
|
||||
if (Array.isArray(children)) {
|
||||
// Ensure that inline nodes are surrounded by text nodes to conform to slate schema
|
||||
children = wrapInlinesWithTexts(children);
|
||||
// Merge adjacent text nodes with the same marks to conform to slate schema
|
||||
children = mergeAdjacentTexts(children);
|
||||
}
|
||||
|
||||
/**
|
||||
|
Loading…
x
Reference in New Issue
Block a user