fix: undo/redo buttons now reactively update on editor changes

Add a tick counter that increments on every TipTap transaction,
propagated from TiptapEditor through NoteEditor to FormattingToolbar.
This forces Svelte 5 to re-evaluate canUndo/canRedo state in the
template since plain object method calls aren't tracked reactively.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Frederic Cabassut
2026-03-05 23:00:58 +01:00
co-authored by Claude Opus 4.6
parent 26b3ae26c3
commit 6f3f7c7e03
3 changed files with 15 additions and 7 deletions
+9 -5
View File
@@ -26,10 +26,14 @@
} from 'lucide-svelte';
interface Props {
tick?: number;
editor: Editor | undefined;
}
let { editor }: Props = $props();
let { editor, tick }: Props = $props();
function canUndo() { void tick; return editor?.can().chain().focus().undo().run() ?? false; }
function canRedo() { void tick; return editor?.can().chain().focus().redo().run() ?? false; }
let openDropdown: string | null = $state(null);
let linkUrl: string = $state('');
@@ -111,8 +115,8 @@
<!-- History -->
<button
onclick={() => editor?.chain().focus().undo().run()}
disabled={!editor?.can().undo()}
class={btnClass(false, !editor?.can().undo())}
disabled={!canUndo()}
class={btnClass(false, !canUndo())}
title="Undo (Ctrl+Z)"
data-testid="format-undo"
>
@@ -120,8 +124,8 @@
</button>
<button
onclick={() => editor?.chain().focus().redo().run()}
disabled={!editor?.can().redo()}
class={btnClass(false, !editor?.can().redo())}
disabled={!canRedo()}
class={btnClass(false, !canRedo())}
title="Redo (Ctrl+Shift+Z)"
data-testid="format-redo"
>
+3 -1
View File
@@ -29,6 +29,7 @@
let rawMarkdownMode = $state(false);
let textareaEl: HTMLTextAreaElement | undefined = $state();
let tiptapEditor: Editor | undefined = $state();
let editorTick = $state(0);
let bgStyle = $state('');
$effect(() => {
@@ -112,13 +113,14 @@
{content}
onUpdate={(md) => (content = md)}
onEditor={(e) => (tiptapEditor = e)}
onTransaction={() => editorTick++}
placeholder="Take a note..."
/>
{/if}
<!-- Formatting toolbar -->
{#if !rawMarkdownMode && !checklistMode}
<FormattingToolbar editor={tiptapEditor} />
<FormattingToolbar editor={tiptapEditor} tick={editorTick} />
{/if}
<!-- Toolbar -->
+3 -1
View File
@@ -12,10 +12,11 @@
content: string;
onUpdate: (markdown: string) => void;
onEditor?: (editor: Editor) => void;
onTransaction?: () => void;
placeholder?: string;
}
let { content, onUpdate, onEditor, placeholder = 'Take a note...' }: Props = $props();
let { content, onUpdate, onEditor, onTransaction, placeholder = 'Take a note...' }: Props = $props();
let element: HTMLDivElement | undefined = $state();
let editor: Editor | undefined = $state();
@@ -38,6 +39,7 @@
onTransaction: () => {
// Trigger Svelte reactivity for active state checks
editor = editor;
onTransaction?.();
}
});