mirror of
https://github.com/bretzel-app/crumbs.git
synced 2026-10-12 12:06:57 +02:00
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:
co-authored by
Claude Opus 4.6
parent
26b3ae26c3
commit
6f3f7c7e03
@@ -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"
|
||||
>
|
||||
|
||||
@@ -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 -->
|
||||
|
||||
@@ -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?.();
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user