fix(editor): make placeholder mount-only instead of a dead reactive dep

extensions was memoized on [placeholder], implying a live placeholder update,
but useEditor runs with empty deps and tiptap's setOptions merges options
without re-registering extensions — so a changed placeholder never reaches the
already-installed Placeholder plugin (verified: data-placeholder stays at the
mount value across a prop change). Drop placeholder from the deps to match the
autoFocus mount-only decision, removing the misleading reactivity signal and the
per-change rebuild of the whole extension array.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Sergey Kozyrenko
2026-07-02 02:26:34 +07:00
co-authored by Claude Opus 4.8
parent 4ddb76f9ff
commit c4eb983c44
@@ -114,7 +114,12 @@ function MarkdownEditor({
const hasResetInitialHistoryRef = useRef(false);
const extensions = useMemo(() => createMarkdownExtensions(placeholder), [placeholder]);
// `placeholder` is captured at mount, like the native <input placeholder>. tiptap's setOptions merges
// options without re-registering extensions, so a later change can't reach the already-built Placeholder
// plugin regardless; keeping it out of the deps makes that explicit and stops rebuilding the whole
// extension array on every placeholder change.
// eslint-disable-next-line react-hooks/exhaustive-deps
const extensions = useMemo(() => createMarkdownExtensions(placeholder), []);
// tiptap invokes onBlur/onUpdate from its live options ref, so these closures always read the latest props.
const editor = useEditor({