Skip to content

Commit e05f61a

Browse files
Fix spurious saves on note open with discrete editor update
The editor.update() in InitialContentPlugin was async (batched), causing onInitComplete to fire before the import settled. The OnChangeMarkdownPlugin baseline was recorded from the pre-import state, so the first post-init update saw a different export and triggered onChange, causing every note open to schedule a save. Fix: use { discrete: true } so the import settles synchronously before the baseline is recorded.
1 parent 9fcb846 commit e05f61a

1 file changed

Lines changed: 35 additions & 29 deletions

File tree

src/components/editor/plugins/initial-content-plugin.tsx

Lines changed: 35 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -26,39 +26,45 @@ export default function InitialContentPlugin({
2626
const mode = isNew ? "new" : !markdown.trim() ? "empty" : "existing";
2727
console.log(`[editor:init] mode=${mode} markdown=${markdown.length} chars`);
2828

29-
editor.update(() => {
30-
if (isNew) {
31-
if (markdown === "- [ ] ") {
32-
// Todo mode: create an empty checklist item directly
33-
// (marked can't parse "- [ ] " without text after it)
34-
const root = $getRoot();
35-
root.clear();
36-
const checkList = $createListNode("check");
37-
const checkItem = $createListItemNode(false);
38-
checkList.append(checkItem);
39-
root.append(checkList);
40-
checkItem.selectEnd();
29+
editor.update(
30+
() => {
31+
if (isNew) {
32+
if (markdown === "- [ ] ") {
33+
// Todo mode: create an empty checklist item directly
34+
// (marked can't parse "- [ ] " without text after it)
35+
const root = $getRoot();
36+
root.clear();
37+
const checkList = $createListNode("check");
38+
const checkItem = $createListItemNode(false);
39+
checkList.append(checkItem);
40+
root.append(checkList);
41+
checkItem.selectEnd();
42+
} else {
43+
// Normal new note: import markdown and place cursor at heading end
44+
$importMarkdown(markdown);
45+
const root = $getRoot();
46+
const firstChild = root.getFirstChild();
47+
if ($isHeadingNode(firstChild)) {
48+
firstChild.selectEnd();
49+
}
50+
}
51+
} else if (!markdown.trim()) {
52+
// Empty existing note: leave the default empty paragraph.
53+
// (Lexical initializes with one ParagraphNode by default.)
54+
$setSelection(null);
4155
} else {
42-
// Normal new note: import markdown and place cursor at heading end
4356
$importMarkdown(markdown);
44-
const root = $getRoot();
45-
const firstChild = root.getFirstChild();
46-
if ($isHeadingNode(firstChild)) {
47-
firstChild.selectEnd();
48-
}
57+
$setSelection(null);
4958
}
50-
} else if (!markdown.trim()) {
51-
// Empty existing note: leave the default empty paragraph.
52-
// (Lexical initializes with one ParagraphNode by default.)
53-
$setSelection(null);
54-
} else {
55-
$importMarkdown(markdown);
56-
$setSelection(null);
57-
}
5859

59-
const root = $getRoot();
60-
console.log(`[editor:init] imported ${root.getChildrenSize()} nodes`);
61-
});
60+
const root = $getRoot();
61+
console.log(`[editor:init] imported ${root.getChildrenSize()} nodes`);
62+
},
63+
// Use discrete so the update settles synchronously before onInitComplete.
64+
// This ensures the OnChangeMarkdownPlugin baseline is recorded from the
65+
// post-import state, not the pre-import state.
66+
{ discrete: true },
67+
);
6268

6369
onInitComplete();
6470
}, [editor, isNew, markdown, onInitComplete]);

0 commit comments

Comments
 (0)