diff --git a/frontend/src/lib/components/PersonMentionEditor.svelte b/frontend/src/lib/components/PersonMentionEditor.svelte index 592fdd7d..1347f545 100644 --- a/frontend/src/lib/components/PersonMentionEditor.svelte +++ b/frontend/src/lib/components/PersonMentionEditor.svelte @@ -241,8 +241,15 @@ onDestroy(() => { // Keep editor in sync with the reactive `disabled` prop. Tiptap's setEditable // flips contenteditable on the inner DOM and stops accepting input — matches // the textarea's old `disabled` semantics for keyboard users (WCAG 2.1.1). +// +// Guard: setEditable triggers a ProseMirror transaction which fires onUpdate; +// onUpdate writes through bind:value / bind:mentionedPersons. Without this +// idempotence check, the effect would loop on every prop pass-through. $effect(() => { - editor?.setEditable(!disabled); + const shouldBeEditable = !disabled; + if (editor && editor.isEditable !== shouldBeEditable) { + editor.setEditable(shouldBeEditable); + } });