fix(PersonMentionEditor): guard setEditable effect against re-entry loop
The disabled-state effect calls editor.setEditable, which triggers a
ProseMirror transaction → onUpdate → bind:value/mentionedPersons writes →
host re-render → child prop pass-through → effect re-fires. Without an
idempotence check, this exceeds Svelte's effect_update_depth and crashes
every consuming spec (TranscriptionBlock 22/22). Compare editor.isEditable
against the desired value first; only call setEditable when it actually
needs to change.
Follow-up to 6ef888a1.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -241,8 +241,15 @@ onDestroy(() => {
|
|||||||
// Keep editor in sync with the reactive `disabled` prop. Tiptap's setEditable
|
// Keep editor in sync with the reactive `disabled` prop. Tiptap's setEditable
|
||||||
// flips contenteditable on the inner DOM and stops accepting input — matches
|
// flips contenteditable on the inner DOM and stops accepting input — matches
|
||||||
// the textarea's old `disabled` semantics for keyboard users (WCAG 2.1.1).
|
// 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(() => {
|
$effect(() => {
|
||||||
editor?.setEditable(!disabled);
|
const shouldBeEditable = !disabled;
|
||||||
|
if (editor && editor.isEditable !== shouldBeEditable) {
|
||||||
|
editor.setEditable(shouldBeEditable);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user