diff --git a/packages/lexical-playground/__tests__/e2e/Tables.spec.mjs b/packages/lexical-playground/__tests__/e2e/Tables.spec.mjs index cca10f327de..19a6d907c7a 100644 --- a/packages/lexical-playground/__tests__/e2e/Tables.spec.mjs +++ b/packages/lexical-playground/__tests__/e2e/Tables.spec.mjs @@ -1233,21 +1233,21 @@ test.describe.parallel('Tables', () => {

aa

-

bb

+

bb

-

cc

+

cc

-

d

+

d

-

e

+

e

-

f

+

f

diff --git a/packages/lexical-react/src/__tests__/unit/Collaboration.test.ts b/packages/lexical-react/src/__tests__/unit/Collaboration.test.ts index 3291750ac60..7e5b7dd2e67 100644 --- a/packages/lexical-react/src/__tests__/unit/Collaboration.test.ts +++ b/packages/lexical-react/src/__tests__/unit/Collaboration.test.ts @@ -7,6 +7,7 @@ */ import { + $createLineBreakNode, $createParagraphNode, $createTextNode, $getRoot, @@ -290,6 +291,55 @@ describe('Collaboration', () => { client2.stop(); }); + it('Should not sync direction of element node', async () => { + const connector = createTestConnection(); + const client1 = connector.createClient('1'); + const client2 = connector.createClient('2'); + client1.start(container!); + client2.start(container!); + + await expectCorrectInitialContent(client1, client2); + + // Add paragraph with RTL text, then another with a non-TextNode child + await waitForReact(() => { + client1.update(() => { + const root = $getRoot().clear(); + root.append( + $createParagraphNode().append($createTextNode('فرعي')), + $createParagraphNode().append($createLineBreakNode()), + ); + }); + }); + + // Check that the second paragraph has RTL direction + expect(client1.getHTML()).toEqual( + '

فرعي



', + ); + expect(client2.getHTML()).toEqual(client1.getHTML()); + + // Mark the second paragraph's child as dirty to force the reconciler to run. + await waitForReact(() => { + client1.update(() => { + const pargraph = $getRoot().getChildAtIndex(1)!; + const lineBreak = pargraph.getFirstChildOrThrow(); + lineBreak.markDirty(); + }); + }); + + // There was no activeEditorDirection when processing this node, so direction should be set back to null. + expect(client1.getHTML()).toEqual( + '

فرعي



', + ); + + // Check that the second paragraph still has RTL direction on client 2, as __dir is not synced. + expect(client2.getHTML()).toEqual( + '

فرعي



', + ); + + client1.stop(); + client2.stop(); + }); + it('Should allow the passing of arbitrary awareness data', async () => { const connector = createTestConnection(); diff --git a/packages/lexical-yjs/src/Utils.ts b/packages/lexical-yjs/src/Utils.ts index f3c5153c6ed..6c1560ca6c3 100644 --- a/packages/lexical-yjs/src/Utils.ts +++ b/packages/lexical-yjs/src/Utils.ts @@ -51,6 +51,7 @@ const elementExcludedProperties = new Set([ '__first', '__last', '__size', + '__dir', ]); const rootExcludedProperties = new Set(['__cachedText']); const textExcludedProperties = new Set(['__text']); diff --git a/packages/lexical/src/__tests__/unit/LexicalReconciler.test.ts b/packages/lexical/src/__tests__/unit/LexicalReconciler.test.ts new file mode 100644 index 00000000000..1f92cdc2db8 --- /dev/null +++ b/packages/lexical/src/__tests__/unit/LexicalReconciler.test.ts @@ -0,0 +1,53 @@ +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + */ + +import { + $createLineBreakNode, + $createParagraphNode, + $createTextNode, + $getRoot, + ParagraphNode, +} from 'lexical'; + +import {initializeUnitTest} from '../utils'; + +describe('LexicalReconciler', () => { + initializeUnitTest((testEnv) => { + test('Should use activeEditorDirection as the direction for a node with no directioned text', async () => { + const {editor} = testEnv; + + editor.update(() => { + const root = $getRoot().clear(); + root.append( + $createParagraphNode().append($createTextNode('فرعي')), + $createParagraphNode().append($createTextNode('Hello')), + $createParagraphNode().append($createLineBreakNode()), + ); + }); + + // The third paragraph has no directioned text, so it should be set to the direction of the previous sibling. + let para3Dir = editor.read(() => { + return $getRoot().getChildAtIndex(2)!.getDirection(); + }); + expect(para3Dir).toEqual('ltr'); + + // Mark the first and third paragraphs as dirty to force the reconciler to run. + editor.update(() => { + $getRoot().getChildAtIndex(0)!.markDirty(); + $getRoot().getChildAtIndex(2)!.markDirty(); + }); + + // Note: this is arguably a bug. It would be preferable for the node to keep its LTR direction. Added as a + // test so that the behaviour is at least documented. + para3Dir = editor.read(() => { + return $getRoot().getChildAtIndex(2)!.getDirection(); + }); + expect(para3Dir).toEqual('rtl'); + }); + }); +});