mirror of
https://github.com/BookStackApp/BookStack.git
synced 2026-10-12 02:01:37 +00:00
Lexical: Fixed difference in line break in-editor & on export
Aligned the linebreak exportdom behaviour to align with how the reconciler displays line breaks in the editor, by adding an extra line break to each series of line breaks, so they're now visually the same across editor and export.
This commit is contained in:
@@ -41,6 +41,7 @@ import {ImageNode} from "@lexical/rich-text/LexicalImageNode";
|
||||
import {MediaNode} from "@lexical/rich-text/LexicalMediaNode";
|
||||
import {DiagramNode} from "@lexical/rich-text/LexicalDiagramNode";
|
||||
import {DiagramDecorator} from "../../../../ui/decorators/DiagramDecorator";
|
||||
import {$generateHtmlFromNodes} from "@lexical/html";
|
||||
|
||||
type TestEnv = {
|
||||
readonly container: HTMLDivElement;
|
||||
@@ -768,7 +769,14 @@ export function html(
|
||||
}
|
||||
|
||||
export function expectHtmlToBeEqual(expected: string, actual: string): void {
|
||||
expect(formatHtml(expected)).toBe(formatHtml(actual));
|
||||
expect(formatHtml(actual)).toBe(formatHtml(expected));
|
||||
}
|
||||
|
||||
export function expectEditorHtmlToBeEqual(editor: LexicalEditor, expected: string): void {
|
||||
const html = editor.read(() => {
|
||||
return $generateHtmlFromNodes(editor, null);
|
||||
});
|
||||
expect(formatHtml(html)).toBe(formatHtml(expected));
|
||||
}
|
||||
|
||||
type nodeTextShape = {
|
||||
|
||||
@@ -6,10 +6,10 @@
|
||||
*
|
||||
*/
|
||||
|
||||
import type {KlassConstructor} from '../LexicalEditor';
|
||||
import {KlassConstructor, LexicalEditor} from '../LexicalEditor';
|
||||
import type {
|
||||
DOMConversionMap,
|
||||
DOMConversionOutput,
|
||||
DOMConversionOutput, DOMExportOutput,
|
||||
NodeKey,
|
||||
SerializedLexicalNode,
|
||||
} from '../LexicalNode';
|
||||
@@ -43,6 +43,25 @@ export class LineBreakNode extends LexicalNode {
|
||||
return document.createElement('br');
|
||||
}
|
||||
|
||||
exportDOM(editor: LexicalEditor): DOMExportOutput {
|
||||
const output = super.exportDOM(editor);
|
||||
const parent = this.getParent();
|
||||
|
||||
// We insert an extra line break when the line break is the last child of a block node
|
||||
// so that a line break is properly represented as an empty line, which mirrors the in-editor
|
||||
// behaviour, where it's handled at the reconciliation phase
|
||||
if (parent && !parent.isInline() && parent.getLastChild()?.getKey() === this.getKey()) {
|
||||
output.after = (el) => {
|
||||
if (el instanceof HTMLElement) {
|
||||
el.before(document.createElement('br'), el);
|
||||
}
|
||||
return null;
|
||||
};
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
updateDOM(): false {
|
||||
return false;
|
||||
}
|
||||
|
||||
+49
-2
@@ -6,9 +6,22 @@
|
||||
*
|
||||
*/
|
||||
|
||||
import {$createLineBreakNode, $isLineBreakNode} from 'lexical';
|
||||
import {
|
||||
$createLineBreakNode,
|
||||
$createParagraphNode,
|
||||
$createTextNode,
|
||||
$getRoot,
|
||||
$isLineBreakNode,
|
||||
ParagraphNode
|
||||
} from 'lexical';
|
||||
|
||||
import {initializeUnitTest} from '../../../__tests__/utils';
|
||||
import {
|
||||
createTestContext,
|
||||
dispatchKeydownEventForSelectedNode, expectEditorHtmlToBeEqual,
|
||||
expectNodeShapeToMatch,
|
||||
initializeUnitTest
|
||||
} from '../../../__tests__/utils';
|
||||
import {registerRichText} from "@lexical/rich-text";
|
||||
|
||||
describe('LexicalLineBreakNode tests', () => {
|
||||
initializeUnitTest((testEnv) => {
|
||||
@@ -71,4 +84,38 @@ describe('LexicalLineBreakNode tests', () => {
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('LineBreakNode.exportDOM()', () => {
|
||||
test('first linebreaks are represented as a double break on export', () => {
|
||||
const {editor} = createTestContext();
|
||||
registerRichText(editor);
|
||||
|
||||
let textNode;
|
||||
let paragraph!: ParagraphNode;
|
||||
|
||||
editor.updateAndCommit(() => {
|
||||
paragraph = $createParagraphNode();
|
||||
textNode = $createTextNode('hello');
|
||||
paragraph.append(textNode);
|
||||
|
||||
$getRoot().append(paragraph);
|
||||
textNode.selectEnd();
|
||||
});
|
||||
|
||||
dispatchKeydownEventForSelectedNode(editor, 'Enter', {shiftKey: true});
|
||||
|
||||
expectNodeShapeToMatch(editor, [
|
||||
{type: 'paragraph', children: [
|
||||
{text: 'hello'},
|
||||
{type: 'linebreak'},
|
||||
]}
|
||||
]);
|
||||
expectEditorHtmlToBeEqual(editor, `<p>hello<br><br></p>`);
|
||||
|
||||
dispatchKeydownEventForSelectedNode(editor, 'Enter', {shiftKey: true});
|
||||
dispatchKeydownEventForSelectedNode(editor, 'Enter', {shiftKey: true});
|
||||
|
||||
expectEditorHtmlToBeEqual(editor, `<p>hello<br><br><br><br></p>`);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user