From c22b88ee7cf422012752de452665c5b1040e29ed Mon Sep 17 00:00:00 2001 From: Bhavesh Rawat Date: Fri, 17 Apr 2026 08:41:24 +0530 Subject: [PATCH] fix: * stale editor toolbar * and loosing formatting when sinking --- package/components/editor-utils.tsx | 11 ++++++++-- package/extensions/d-block/dblock.ts | 32 +++++++++++++++++++--------- 2 files changed, 31 insertions(+), 12 deletions(-) diff --git a/package/components/editor-utils.tsx b/package/components/editor-utils.tsx index f98657bf..114fbf87 100644 --- a/package/components/editor-utils.tsx +++ b/package/components/editor-utils.tsx @@ -246,11 +246,18 @@ export const useEditorToolbar = ({ }); }; updateMarkStates(); - // Only update mark states on selection changes — not every transaction. - // Text input transactions don't change which marks are active at the cursor. + // Update on selection changes and when storedMarks change (e.g. toggling + // bold on an empty paragraph, or after sink/lift restructures the doc). editor.on('selectionUpdate', updateMarkStates); + const onTransaction = ({ transaction }: { transaction: any }) => { + if (transaction.storedMarksSet) { + updateMarkStates(); + } + }; + editor.on('transaction', onTransaction); return () => { editor.off('selectionUpdate', updateMarkStates); + editor.off('transaction', onTransaction); }; }, [editor]); diff --git a/package/extensions/d-block/dblock.ts b/package/extensions/d-block/dblock.ts index 5ca0bab8..9468d627 100644 --- a/package/extensions/d-block/dblock.ts +++ b/package/extensions/d-block/dblock.ts @@ -150,20 +150,22 @@ export const DBlock = Node.create({ const node = $from.node(d); if (node.type.name === 'listItem') { - // Try to sink the list item - // If it's the first item, sinkListItem will return false and nothing happens + // Preserve active marks before sinking — sinkListItem restructures + // the document which clears storedMarks, causing formatting loss. + const marks = editor.state.storedMarks || selection.$from.marks(); editor.commands.sinkListItem('listItem'); - - // Always return true to prevent browser Tab behavior + if (marks.length) { + editor.view.dispatch(editor.state.tr.setStoredMarks(marks)); + } return true; } if (node.type.name === 'taskItem') { - // Try to sink the task item - // If it's the first item, sinkListItem will return false and nothing happens + const marks = editor.state.storedMarks || selection.$from.marks(); editor.commands.sinkListItem('taskItem'); - - // Always return true to prevent browser Tab behavior + if (marks.length) { + editor.view.dispatch(editor.state.tr.setStoredMarks(marks)); + } return true; } } @@ -198,10 +200,20 @@ export const DBlock = Node.create({ const node = $from.node(d); if (node.type.name === 'listItem') { - return editor.commands.liftListItem('listItem'); + const marks = editor.state.storedMarks || $from.marks(); + const result = editor.commands.liftListItem('listItem'); + if (marks.length) { + editor.view.dispatch(editor.state.tr.setStoredMarks(marks)); + } + return result; } if (node.type.name === 'taskItem') { - return editor.commands.liftListItem('taskItem'); + const marks = editor.state.storedMarks || $from.marks(); + const result = editor.commands.liftListItem('taskItem'); + if (marks.length) { + editor.view.dispatch(editor.state.tr.setStoredMarks(marks)); + } + return result; } }