Do not display editor block placeholder when disabled

Signed-off-by: Émile Ré <emile@getprobo.com>
This commit is contained in:
Émile Ré
2026-04-01 12:00:23 +04:00
parent 3cba683707
commit 8a25ca27b6

View File

@@ -3,49 +3,91 @@
// that can be found in the LICENSE file.
import { Extension } from "@tiptap/core";
import { Plugin, PluginKey } from "@tiptap/pm/state";
import { Decoration, DecorationSet } from "@tiptap/pm/view";
import { type EditorState, Plugin, PluginKey } from "@tiptap/pm/state";
import { Decoration, DecorationSet, type EditorView } from "@tiptap/pm/view";
const placeholderKey = new PluginKey("placeholder");
function computeDecorations(
state: EditorState,
editable: boolean,
): DecorationSet {
if (!editable) return DecorationSet.empty;
const { selection } = state;
if (!selection.empty) return DecorationSet.empty;
const $pos = selection.$from;
const node = $pos.parent;
if (node.type.name !== "paragraph") return DecorationSet.empty;
if (node.content.size !== 0) return DecorationSet.empty;
if ($pos.depth >= 2) {
const parentName = $pos.node($pos.depth - 1).type.name;
if (
parentName === "listItem"
|| parentName === "tableCell"
|| parentName === "tableHeader"
) {
return DecorationSet.empty;
}
}
const pos = $pos.before($pos.depth);
return DecorationSet.create(state.doc, [
Decoration.node(pos, pos + node.nodeSize, {
"class": "is-empty-focused",
"data-placeholder": "Write or type / for commands\u2026",
}),
]);
}
export const PlaceholderExtension = Extension.create({
name: "placeholder",
addProseMirrorPlugins() {
const { editor } = this;
return [
new Plugin({
key: placeholderKey,
view() {
let lastEditable = editor.isEditable;
return {
update(view: EditorView) {
const editable = editor.isEditable;
if (editable !== lastEditable) {
lastEditable = editable;
view.dispatch(
view.state.tr.setMeta(placeholderKey, true),
);
}
},
};
},
state: {
init(_config, state) {
return computeDecorations(state, editor.isEditable);
},
apply(tr, value, _oldState, newState) {
if (
!tr.docChanged
&& !tr.selectionSet
&& !tr.getMeta(placeholderKey)
) {
return value;
}
return computeDecorations(newState, editor.isEditable);
},
},
props: {
decorations(state) {
const { selection } = state;
if (!selection.empty) return DecorationSet.empty;
const $pos = selection.$from;
const node = $pos.parent;
if (node.type.name !== "paragraph") return DecorationSet.empty;
if (node.content.size !== 0) return DecorationSet.empty;
if ($pos.depth >= 2) {
const parentName = $pos.node($pos.depth - 1).type.name;
if (
parentName === "listItem"
|| parentName === "tableCell"
|| parentName === "tableHeader"
) {
return DecorationSet.empty;
}
}
const pos = $pos.before($pos.depth);
return DecorationSet.create(state.doc, [
Decoration.node(pos, pos + node.nodeSize, {
"class": "is-empty-focused",
"data-placeholder": "Write or type / for commands\u2026",
}),
]);
return placeholderKey.getState(state) as DecorationSet;
},
},
}),