diff --git a/packages/lexical-playground/src/nodes/TableComponent.tsx b/packages/lexical-playground/src/nodes/TableComponent.tsx index 0c1e972e242..e2da147e86b 100644 --- a/packages/lexical-playground/src/nodes/TableComponent.tsx +++ b/packages/lexical-playground/src/nodes/TableComponent.tsx @@ -6,7 +6,7 @@ * */ -import type {EditorState, RangeSelection, TextFormatType} from 'lexical'; +import type {RangeSelection, TextFormatType} from 'lexical'; import { $generateJSONFromSelectedNodes, @@ -204,13 +204,7 @@ function $updateCells( const editorState = cellEditor.parseEditorState(cell.json); cellEditor._headless = true; cellEditor.setEditorState(editorState); - cellEditor.update(() => { - // Complete hack for now - const pendingEditorState = - cellEditor._pendingEditorState as EditorState; - pendingEditorState._flushSync = true; - fn(); - }); + cellEditor.update(fn, {discrete: true}); cellEditor._headless = false; const newJSON = JSON.stringify(cellEditor.getEditorState()); updateTableNode((tableNode) => { diff --git a/packages/lexical/flow/Lexical.js.flow b/packages/lexical/flow/Lexical.js.flow index 4e9ffed1189..f84a9388394 100644 --- a/packages/lexical/flow/Lexical.js.flow +++ b/packages/lexical/flow/Lexical.js.flow @@ -182,6 +182,7 @@ type EditorUpdateOptions = { onUpdate?: () => void, tag?: string, skipTransforms?: true, + discrete?: true, }; type EditorFocusOptions = { defaultSelection?: 'rootStart' | 'rootEnd', diff --git a/packages/lexical/src/LexicalEditor.ts b/packages/lexical/src/LexicalEditor.ts index b1e31bf3069..c7ec33c63a8 100644 --- a/packages/lexical/src/LexicalEditor.ts +++ b/packages/lexical/src/LexicalEditor.ts @@ -60,6 +60,7 @@ export type EditorUpdateOptions = { onUpdate?: () => void; skipTransforms?: true; tag?: string; + discrete?: true; }; export type EditorSetOptions = { diff --git a/packages/lexical/src/LexicalUpdates.ts b/packages/lexical/src/LexicalUpdates.ts index f183c9d8106..7d2b54b025a 100644 --- a/packages/lexical/src/LexicalUpdates.ts +++ b/packages/lexical/src/LexicalUpdates.ts @@ -765,6 +765,7 @@ function beginUpdate( let onUpdate; let tag; let skipTransforms = false; + let discrete = false; if (options !== undefined) { onUpdate = options.onUpdate; @@ -775,6 +776,7 @@ function beginUpdate( } skipTransforms = options.skipTransforms || false; + discrete = options.discrete || false; } if (onUpdate) { @@ -790,6 +792,7 @@ function beginUpdate( cloneEditorState(currentEditorState); editorStateWasCloned = true; } + pendingEditorState._flushSync = discrete; const previousActiveEditorState = activeEditorState; const previousReadOnlyMode = isReadOnlyMode; diff --git a/packages/lexical/src/__tests__/unit/LexicalEditor.test.tsx b/packages/lexical/src/__tests__/unit/LexicalEditor.test.tsx index 28e00080a8c..7ccf17337fd 100644 --- a/packages/lexical/src/__tests__/unit/LexicalEditor.test.tsx +++ b/packages/lexical/src/__tests__/unit/LexicalEditor.test.tsx @@ -2142,4 +2142,26 @@ describe('LexicalEditor tests', () => { expect(nodeTransformListener).toHaveBeenCalledTimes(1); expect(mutationListener).toHaveBeenCalledTimes(1); }); + + it('can use flushSync for synchronous updates', () => { + init(); + const onUpdate = jest.fn(); + editor.registerUpdateListener(onUpdate); + editor.update( + () => { + $getRoot().append( + $createParagraphNode().append($createTextNode('Sync update')), + ); + }, + { + discrete: true, + }, + ); + + const textContent = editor + .getEditorState() + .read(() => $getRoot().getTextContent()); + expect(textContent).toBe('Sync update'); + expect(onUpdate).toHaveBeenCalledTimes(1); + }); });