Skip to content

Commit 654a7a5

Browse files
committed
Lexical: Removed reconciler level direction handling
- Updated tests to consider changes
1 parent dba8ab9 commit 654a7a5

22 files changed

+329
-459
lines changed

resources/js/wysiwyg/lexical/core/LexicalReconciler.ts

Lines changed: 1 addition & 114 deletions
Original file line numberDiff line numberDiff line change
@@ -42,14 +42,12 @@ import {
4242
$textContentRequiresDoubleLinebreakAtEnd,
4343
cloneDecorators,
4444
getElementByKeyOrThrow,
45-
getTextDirection,
4645
setMutatedNode,
4746
} from './LexicalUtils';
4847

4948
type IntentionallyMarkedAsDirtyElement = boolean;
5049

5150
let subTreeTextContent = '';
52-
let subTreeDirectionedTextContent = '';
5351
let subTreeTextFormat: number | null = null;
5452
let subTreeTextStyle: string = '';
5553
let editorTextContent = '';
@@ -59,7 +57,6 @@ let activeEditorNodes: RegisteredNodes;
5957
let treatAllNodesAsDirty = false;
6058
let activeEditorStateReadOnly = false;
6159
let activeMutationListeners: MutationListeners;
62-
let activeTextDirection: 'ltr' | 'rtl' | null = null;
6360
let activeDirtyElements: Map<NodeKey, IntentionallyMarkedAsDirtyElement>;
6461
let activeDirtyLeaves: Set<NodeKey>;
6562
let activePrevNodeMap: NodeMap;
@@ -197,7 +194,7 @@ function $createNode(
197194
if (childrenSize !== 0) {
198195
const endIndex = childrenSize - 1;
199196
const children = createChildrenArray(node, activeNextNodeMap);
200-
$createChildrenWithDirection(children, endIndex, node, dom);
197+
$createChildren(children, node, 0, endIndex, dom, null);
201198
}
202199
const format = node.__format;
203200

@@ -222,10 +219,6 @@ function $createNode(
222219
}
223220
// Decorators are always non editable
224221
dom.contentEditable = 'false';
225-
} else if ($isTextNode(node)) {
226-
if (!node.isDirectionless()) {
227-
subTreeDirectionedTextContent += text;
228-
}
229222
}
230223
subTreeTextContent += text;
231224
editorTextContent += text;
@@ -261,19 +254,6 @@ function $createNode(
261254
return dom;
262255
}
263256

264-
function $createChildrenWithDirection(
265-
children: Array<NodeKey>,
266-
endIndex: number,
267-
element: ElementNode,
268-
dom: HTMLElement,
269-
): void {
270-
const previousSubTreeDirectionedTextContent = subTreeDirectionedTextContent;
271-
subTreeDirectionedTextContent = '';
272-
$createChildren(children, element, 0, endIndex, dom, null);
273-
reconcileBlockDirection(element, dom);
274-
subTreeDirectionedTextContent = previousSubTreeDirectionedTextContent;
275-
}
276-
277257
function $createChildren(
278258
children: Array<NodeKey>,
279259
element: ElementNode,
@@ -388,93 +368,16 @@ function reconcileParagraphStyle(element: ElementNode): void {
388368
}
389369
}
390370

391-
function reconcileBlockDirection(element: ElementNode, dom: HTMLElement): void {
392-
const previousSubTreeDirectionTextContent: string =
393-
// @ts-expect-error: internal field
394-
dom.__lexicalDirTextContent;
395-
// @ts-expect-error: internal field
396-
const previousDirection: string = dom.__lexicalDir;
397-
398-
if (
399-
previousSubTreeDirectionTextContent !== subTreeDirectionedTextContent ||
400-
previousDirection !== activeTextDirection
401-
) {
402-
const hasEmptyDirectionedTextContent = subTreeDirectionedTextContent === '';
403-
const direction = hasEmptyDirectionedTextContent
404-
? activeTextDirection
405-
: getTextDirection(subTreeDirectionedTextContent);
406-
407-
if (direction !== previousDirection) {
408-
const classList = dom.classList;
409-
const theme = activeEditorConfig.theme;
410-
let previousDirectionTheme =
411-
previousDirection !== null ? theme[previousDirection] : undefined;
412-
let nextDirectionTheme =
413-
direction !== null ? theme[direction] : undefined;
414-
415-
// Remove the old theme classes if they exist
416-
if (previousDirectionTheme !== undefined) {
417-
if (typeof previousDirectionTheme === 'string') {
418-
const classNamesArr = normalizeClassNames(previousDirectionTheme);
419-
previousDirectionTheme = theme[previousDirection] = classNamesArr;
420-
}
421-
422-
// @ts-ignore: intentional
423-
classList.remove(...previousDirectionTheme);
424-
}
425-
426-
if (
427-
direction === null ||
428-
(hasEmptyDirectionedTextContent && direction === 'ltr')
429-
) {
430-
// Remove direction
431-
dom.removeAttribute('dir');
432-
} else {
433-
// Apply the new theme classes if they exist
434-
if (nextDirectionTheme !== undefined) {
435-
if (typeof nextDirectionTheme === 'string') {
436-
const classNamesArr = normalizeClassNames(nextDirectionTheme);
437-
// @ts-expect-error: intentional
438-
nextDirectionTheme = theme[direction] = classNamesArr;
439-
}
440-
441-
if (nextDirectionTheme !== undefined) {
442-
classList.add(...nextDirectionTheme);
443-
}
444-
}
445-
446-
// Update direction
447-
dom.dir = direction;
448-
}
449-
450-
if (!activeEditorStateReadOnly) {
451-
const writableNode = element.getWritable();
452-
writableNode.__dir = direction;
453-
}
454-
}
455-
456-
activeTextDirection = direction;
457-
// @ts-expect-error: internal field
458-
dom.__lexicalDirTextContent = subTreeDirectionedTextContent;
459-
// @ts-expect-error: internal field
460-
dom.__lexicalDir = direction;
461-
}
462-
}
463-
464371
function $reconcileChildrenWithDirection(
465372
prevElement: ElementNode,
466373
nextElement: ElementNode,
467374
dom: HTMLElement,
468375
): void {
469-
const previousSubTreeDirectionTextContent = subTreeDirectionedTextContent;
470-
subTreeDirectionedTextContent = '';
471376
subTreeTextFormat = null;
472377
subTreeTextStyle = '';
473378
$reconcileChildren(prevElement, nextElement, dom);
474-
reconcileBlockDirection(nextElement, dom);
475379
reconcileParagraphFormat(nextElement);
476380
reconcileParagraphStyle(nextElement);
477-
subTreeDirectionedTextContent = previousSubTreeDirectionTextContent;
478381
}
479382

480383
function createChildrenArray(
@@ -624,20 +527,9 @@ function $reconcileNode(
624527
subTreeTextContent += previousSubTreeTextContent;
625528
editorTextContent += previousSubTreeTextContent;
626529
}
627-
628-
// @ts-expect-error: internal field
629-
const previousSubTreeDirectionTextContent = dom.__lexicalDirTextContent;
630-
631-
if (previousSubTreeDirectionTextContent !== undefined) {
632-
subTreeDirectionedTextContent += previousSubTreeDirectionTextContent;
633-
}
634530
} else {
635531
const text = prevNode.getTextContent();
636532

637-
if ($isTextNode(prevNode) && !prevNode.isDirectionless()) {
638-
subTreeDirectionedTextContent += text;
639-
}
640-
641533
editorTextContent += text;
642534
subTreeTextContent += text;
643535
}
@@ -702,9 +594,6 @@ function $reconcileNode(
702594
if (decorator !== null) {
703595
reconcileDecorator(key, decorator);
704596
}
705-
} else if ($isTextNode(nextNode) && !nextNode.isDirectionless()) {
706-
// Handle text content, for LTR, LTR cases.
707-
subTreeDirectionedTextContent += text;
708597
}
709598

710599
subTreeTextContent += text;
@@ -871,11 +760,9 @@ export function $reconcileRoot(
871760
// The cache must be rebuilt during reconciliation to account for any changes.
872761
subTreeTextContent = '';
873762
editorTextContent = '';
874-
subTreeDirectionedTextContent = '';
875763
// Rather than pass around a load of arguments through the stack recursively
876764
// we instead set them as bindings within the scope of the module.
877765
treatAllNodesAsDirty = dirtyType === FULL_RECONCILE;
878-
activeTextDirection = null;
879766
activeEditor = editor;
880767
activeEditorConfig = editor._config;
881768
activeEditorNodes = editor._nodes;

resources/js/wysiwyg/lexical/core/__tests__/unit/HTMLCopyAndPaste.test.ts

Lines changed: 6 additions & 6 deletions
Large diffs are not rendered by default.

resources/js/wysiwyg/lexical/core/__tests__/unit/LexicalEditor.test.ts

Lines changed: 19 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -258,7 +258,7 @@ describe('LexicalEditor tests', () => {
258258
await Promise.resolve().then();
259259

260260
expect(container.innerHTML).toBe(
261-
'<div style="user-select: text; white-space: pre-wrap; word-break: break-word;" data-lexical-editor="true"><p dir="ltr"><span data-lexical-text="true">This works!</span></p></div>',
261+
'<div style="user-select: text; white-space: pre-wrap; word-break: break-word;" data-lexical-editor="true"><p><span data-lexical-text="true">This works!</span></p></div>',
262262
);
263263

264264
const initialEditorState = initialEditor.getEditorState();
@@ -276,7 +276,7 @@ describe('LexicalEditor tests', () => {
276276

277277
expect(editor.getEditorState()).toEqual(initialEditorState);
278278
expect(container.innerHTML).toBe(
279-
'<div style="user-select: text; white-space: pre-wrap; word-break: break-word;" data-lexical-editor="true"><p dir="ltr"><span data-lexical-text="true">This works!</span></p></div>',
279+
'<div style="user-select: text; white-space: pre-wrap; word-break: break-word;" data-lexical-editor="true"><p><span data-lexical-text="true">This works!</span></p></div>',
280280
);
281281
});
282282

@@ -520,7 +520,7 @@ describe('LexicalEditor tests', () => {
520520
underlineListener();
521521

522522
expect(container.innerHTML).toBe(
523-
'<div contenteditable="true" style="user-select: text; white-space: pre-wrap; word-break: break-word;" data-lexical-editor="true"><p dir="ltr"><strong class="editor-text-bold editor-text-italic editor-text-underline" data-lexical-text="true">foo</strong></p></div>',
523+
'<div contenteditable="true" style="user-select: text; white-space: pre-wrap; word-break: break-word;" data-lexical-editor="true"><p><strong class="editor-text-bold editor-text-italic editor-text-underline" data-lexical-text="true">foo</strong></p></div>',
524524
);
525525
});
526526

@@ -586,7 +586,7 @@ describe('LexicalEditor tests', () => {
586586
italicsListener();
587587

588588
expect(container.innerHTML).toBe(
589-
'<div contenteditable="true" style="user-select: text; white-space: pre-wrap; word-break: break-word;" data-lexical-editor="true"><p dir="ltr"><strong class="editor-text-bold editor-text-italic" data-lexical-text="true">foo</strong></p></div>',
589+
'<div contenteditable="true" style="user-select: text; white-space: pre-wrap; word-break: break-word;" data-lexical-editor="true"><p><strong class="editor-text-bold editor-text-italic" data-lexical-text="true">foo</strong></p></div>',
590590
);
591591
});
592592

@@ -657,7 +657,7 @@ describe('LexicalEditor tests', () => {
657657
boldFooListener();
658658

659659
expect(container.innerHTML).toBe(
660-
'<div contenteditable="true" style="user-select: text; white-space: pre-wrap; word-break: break-word;" data-lexical-editor="true"><p dir="ltr"><strong class="editor-text-bold" data-lexical-text="true">Foo!!</strong></p></div>',
660+
'<div contenteditable="true" style="user-select: text; white-space: pre-wrap; word-break: break-word;" data-lexical-editor="true"><p><strong class="editor-text-bold" data-lexical-text="true">Foo!!</strong></p></div>',
661661
);
662662
});
663663

@@ -875,7 +875,7 @@ describe('LexicalEditor tests', () => {
875875
editor.setRootElement(element);
876876

877877
expect(container.innerHTML).toBe(
878-
'<div contenteditable="true" style="user-select: text; white-space: pre-wrap; word-break: break-word;" data-lexical-editor="true"><p dir="ltr"><span data-lexical-text="true">This works!</span></p></div>',
878+
'<div contenteditable="true" style="user-select: text; white-space: pre-wrap; word-break: break-word;" data-lexical-editor="true"><p><span data-lexical-text="true">This works!</span></p></div>',
879879
);
880880
});
881881

@@ -897,7 +897,7 @@ describe('LexicalEditor tests', () => {
897897
await Promise.resolve().then();
898898

899899
expect(container.innerHTML).toBe(
900-
'<div contenteditable="true" style="user-select: text; white-space: pre-wrap; word-break: break-word;" data-lexical-editor="true"><p dir="ltr"><span data-lexical-text="true">This works!</span></p></div>',
900+
'<div contenteditable="true" style="user-select: text; white-space: pre-wrap; word-break: break-word;" data-lexical-editor="true"><p><span data-lexical-text="true">This works!</span></p></div>',
901901
);
902902
expect(errorListener).toHaveBeenCalledTimes(0);
903903

@@ -912,7 +912,7 @@ describe('LexicalEditor tests', () => {
912912

913913
expect(errorListener).toHaveBeenCalledTimes(1);
914914
expect(container.innerHTML).toBe(
915-
'<div contenteditable="true" style="user-select: text; white-space: pre-wrap; word-break: break-word;" data-lexical-editor="true"><p dir="ltr"><span data-lexical-text="true">This works!</span></p></div>',
915+
'<div contenteditable="true" style="user-select: text; white-space: pre-wrap; word-break: break-word;" data-lexical-editor="true"><p><span data-lexical-text="true">This works!</span></p></div>',
916916
);
917917
});
918918

@@ -953,7 +953,7 @@ describe('LexicalEditor tests', () => {
953953
editorInstance.commitUpdates();
954954

955955
expect(container.innerHTML).toBe(
956-
'<div contenteditable="true" style="user-select: text; white-space: pre-wrap; word-break: break-word;" data-lexical-editor="true"><p dir="ltr"><span data-lexical-text="true">Not changed</span></p></div>',
956+
'<div contenteditable="true" style="user-select: text; white-space: pre-wrap; word-break: break-word;" data-lexical-editor="true"><p><span data-lexical-text="true">Not changed</span></p></div>',
957957
);
958958

959959
edContainer = document.createElement('span');
@@ -966,7 +966,7 @@ describe('LexicalEditor tests', () => {
966966
expect(rootListener).toHaveBeenCalledTimes(3);
967967
expect(updateListener).toHaveBeenCalledTimes(3);
968968
expect(container.innerHTML).toBe(
969-
'<span contenteditable="true" style="user-select: text; white-space: pre-wrap; word-break: break-word;" data-lexical-editor="true"><p dir="ltr"><span data-lexical-text="true">Change successful</span></p></span>',
969+
'<span contenteditable="true" style="user-select: text; white-space: pre-wrap; word-break: break-word;" data-lexical-editor="true"><p><span data-lexical-text="true">Change successful</span></p></span>',
970970
);
971971
});
972972

@@ -1046,7 +1046,7 @@ describe('LexicalEditor tests', () => {
10461046
it('Parses the nodes of a stringified editor state', async () => {
10471047
expect(parsedRoot).toEqual({
10481048
__cachedText: null,
1049-
__dir: 'ltr',
1049+
__dir: null,
10501050
__first: paragraphKey,
10511051
__format: 0,
10521052
__indent: 0,
@@ -1060,7 +1060,7 @@ describe('LexicalEditor tests', () => {
10601060
__type: 'root',
10611061
});
10621062
expect(parsedParagraph).toEqual({
1063-
__dir: 'ltr',
1063+
__dir: null,
10641064
__first: textKey,
10651065
__format: 0,
10661066
__indent: 0,
@@ -1128,7 +1128,7 @@ describe('LexicalEditor tests', () => {
11281128
it('Parses the nodes of a stringified editor state', async () => {
11291129
expect(parsedRoot).toEqual({
11301130
__cachedText: null,
1131-
__dir: 'ltr',
1131+
__dir: null,
11321132
__first: paragraphKey,
11331133
__format: 0,
11341134
__indent: 0,
@@ -1142,7 +1142,7 @@ describe('LexicalEditor tests', () => {
11421142
__type: 'root',
11431143
});
11441144
expect(parsedParagraph).toEqual({
1145-
__dir: 'ltr',
1145+
__dir: null,
11461146
__first: textKey,
11471147
__format: 0,
11481148
__indent: 0,
@@ -1275,7 +1275,7 @@ describe('LexicalEditor tests', () => {
12751275
expect(editor._editorState._nodeMap.size).toBe(keys.length + 1); // + root
12761276
expect(editor._keyToDOMMap.size).toBe(keys.length + 1); // + root
12771277
expect(container.innerHTML).toBe(
1278-
'<div contenteditable="true" style="user-select: text; white-space: pre-wrap; word-break: break-word;" data-lexical-editor="true"><p><div dir="ltr"><span data-lexical-text="true">A</span><div dir="ltr"><span data-lexical-text="true">B</span></div></div></p></div>',
1278+
'<div contenteditable="true" style="user-select: text; white-space: pre-wrap; word-break: break-word;" data-lexical-editor="true"><p><div><span data-lexical-text="true">A</span><div><span data-lexical-text="true">B</span></div></div></p></div>',
12791279
);
12801280
});
12811281

@@ -1310,7 +1310,7 @@ describe('LexicalEditor tests', () => {
13101310
});
13111311

13121312
expect(container.innerHTML).toBe(
1313-
'<div contenteditable="true" style="user-select: text; white-space: pre-wrap; word-break: break-word;" data-lexical-editor="true"><p><div dir="ltr"><span data-lexical-text="true">B</span><div dir="ltr"><span data-lexical-text="true">A</span></div></div></p></div>',
1313+
'<div contenteditable="true" style="user-select: text; white-space: pre-wrap; word-break: break-word;" data-lexical-editor="true"><p><div><span data-lexical-text="true">B</span><div><span data-lexical-text="true">A</span></div></div></p></div>',
13141314
);
13151315
});
13161316

@@ -1351,7 +1351,7 @@ describe('LexicalEditor tests', () => {
13511351
});
13521352

13531353
expect(container.innerHTML).toBe(
1354-
'<div contenteditable="true" style="user-select: text; white-space: pre-wrap; word-break: break-word;" data-lexical-editor="true"><p><div dir="ltr"><span data-lexical-text="true">A</span><div dir="ltr"><span data-lexical-text="true">C</span></div></div><div dir="ltr"><span data-lexical-text="true">B</span></div></p></div>',
1354+
'<div contenteditable="true" style="user-select: text; white-space: pre-wrap; word-break: break-word;" data-lexical-editor="true"><p><div><span data-lexical-text="true">A</span><div><span data-lexical-text="true">C</span></div></div><div><span data-lexical-text="true">B</span></div></p></div>',
13551355
);
13561356
});
13571357
});
@@ -2294,14 +2294,14 @@ describe('LexicalEditor tests', () => {
22942294
});
22952295

22962296
expect(container.firstElementChild?.innerHTML).toBe(
2297-
'<p dir="ltr"><span data-lexical-text="true">Hello</span><a></a></p>',
2297+
'<p><span data-lexical-text="true">Hello</span><a></a></p>',
22982298
);
22992299
});
23002300

23012301
it('reconciles state without root element', () => {
23022302
editor = createTestEditor({});
23032303
const state = editor.parseEditorState(
2304-
`{"root":{"children":[{"children":[{"detail":0,"format":0,"mode":"normal","style":"","text":"Hello world","type":"text","version":1}],"direction":"ltr","format":"","indent":0,"type":"paragraph","version":1}],"direction":"ltr","format":"","indent":0,"type":"root","version":1}}`,
2304+
`{"root":{"children":[{"children":[{"detail":0,"format":0,"mode":"normal","style":"","text":"Hello world","type":"text","version":1}],"direction":null,"format":"","indent":0,"type":"paragraph","version":1}],"direction":null,"format":"","indent":0,"type":"root","version":1}}`,
23052305
);
23062306
editor.setEditorState(state);
23072307
expect(editor._editorState).toBe(state);

resources/js/wysiwyg/lexical/core/__tests__/unit/LexicalEditorState.test.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ describe('LexicalEditorState tests', () => {
5252

5353
expect(root).toEqual({
5454
__cachedText: 'foo',
55-
__dir: 'ltr',
55+
__dir: null,
5656
__first: '1',
5757
__format: 0,
5858
__indent: 0,
@@ -66,7 +66,7 @@ describe('LexicalEditorState tests', () => {
6666
__type: 'root',
6767
});
6868
expect(paragraph).toEqual({
69-
__dir: 'ltr',
69+
__dir: null,
7070
__first: '2',
7171
__format: 0,
7272
__indent: 0,
@@ -113,7 +113,7 @@ describe('LexicalEditorState tests', () => {
113113
});
114114

115115
expect(JSON.stringify(editor.getEditorState().toJSON())).toEqual(
116-
`{"root":{"children":[{"children":[{"detail":0,"format":0,"mode":"normal","style":"","text":"Hello world","type":"text","version":1}],"direction":"ltr","format":"","indent":0,"type":"paragraph","version":1,"textFormat":0,"textStyle":""}],"direction":"ltr","format":"","indent":0,"type":"root","version":1}}`,
116+
`{"root":{"children":[{"children":[{"detail":0,"format":0,"mode":"normal","style":"","text":"Hello world","type":"text","version":1}],"direction":null,"format":"","indent":0,"type":"paragraph","version":1,"textFormat":0,"textStyle":""}],"direction":null,"format":"","indent":0,"type":"root","version":1}}`,
117117
);
118118
});
119119

0 commit comments

Comments
 (0)