Skip to content

Commit 20ad9f5

Browse files
authored
[lexical] Bug Fix: Implement missing deserialization for flat $config NodeState (#7683)
1 parent cedd6ef commit 20ad9f5

File tree

3 files changed

+48
-5
lines changed

3 files changed

+48
-5
lines changed

packages/lexical/src/LexicalNode.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1147,7 +1147,7 @@ export class LexicalNode {
11471147
updateFromJSON(
11481148
serializedNode: LexicalUpdateJSON<SerializedLexicalNode>,
11491149
): this {
1150-
return $updateStateFromJSON(this, serializedNode[NODE_STATE_KEY]);
1150+
return $updateStateFromJSON(this, serializedNode);
11511151
}
11521152

11531153
/**

packages/lexical/src/LexicalNodeState.ts

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,9 @@ import {
1313
type Klass,
1414
type LexicalNode,
1515
type LexicalNodeConfig,
16+
type LexicalUpdateJSON,
1617
NODE_STATE_KEY,
18+
type SerializedLexicalNode,
1719
type Spread,
1820
type StaticNodeConfigRecord,
1921
} from '.';
@@ -800,7 +802,9 @@ export function $getWritableNodeState<T extends LexicalNode>(
800802
export function $getSharedNodeState<T extends LexicalNode>(
801803
node: T,
802804
): SharedNodeState {
803-
return getRegisteredNodeOrThrow($getEditor(), node.getType()).sharedNodeState;
805+
return node.__state
806+
? node.__state.sharedNodeState
807+
: getRegisteredNodeOrThrow($getEditor(), node.getType()).sharedNodeState;
804808
}
805809

806810
/**
@@ -815,11 +819,21 @@ export function $getSharedNodeState<T extends LexicalNode>(
815819
*/
816820
export function $updateStateFromJSON<T extends LexicalNode>(
817821
node: T,
818-
unknownState: undefined | UnknownStateRecord,
822+
serialized: LexicalUpdateJSON<SerializedLexicalNode>,
819823
): T {
820824
const writable = node.getWritable();
821-
if (unknownState || writable.__state) {
822-
$getWritableNodeState(node).updateFromJSON(unknownState);
825+
const unknownState = serialized[NODE_STATE_KEY];
826+
let parseState = unknownState;
827+
for (const k of $getSharedNodeState(writable).flatKeys) {
828+
if (k in serialized) {
829+
if (parseState === undefined || parseState === unknownState) {
830+
parseState = {...unknownState};
831+
}
832+
parseState[k] = serialized[k as keyof typeof serialized];
833+
}
834+
}
835+
if (writable.__state || parseState) {
836+
$getWritableNodeState(node).updateFromJSON(parseState);
823837
}
824838
return writable;
825839
}

packages/lexical/src/__tests__/unit/LexicalNodeState.test.ts

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -236,6 +236,35 @@ describe('LexicalNode state', () => {
236236
});
237237
});
238238

239+
test('flat config serialization round-trip', () => {
240+
const {editor} = testEnv;
241+
editor.update(() => {
242+
const flatJSON: LexicalExportJSON<StateNode> = {
243+
[NODE_STATE_KEY]: {boolState: true},
244+
numberState: 2,
245+
type: 'state',
246+
version: 1,
247+
};
248+
const nestedJSON: LexicalExportJSON<StateNode> = {
249+
[NODE_STATE_KEY]: {boolState: true, numberState: 2},
250+
type: 'state',
251+
version: 1,
252+
};
253+
const bothJSON: LexicalExportJSON<StateNode> = {
254+
[NODE_STATE_KEY]: {boolState: true, numberState: 3},
255+
numberState: 2,
256+
type: 'state',
257+
version: 1,
258+
};
259+
for (const doc of [flatJSON, nestedJSON, bothJSON]) {
260+
const node = StateNode.importJSON(doc);
261+
expect(node.exportJSON()).toEqual(flatJSON);
262+
expect($getState(node, boolState)).toBe(true);
263+
expect($getState(node, numberState)).toBe(2);
264+
}
265+
});
266+
});
267+
239268
test('default value should not be exported', async () => {
240269
const {editor} = testEnv;
241270
editor.update(() => {

0 commit comments

Comments
 (0)