mirror of
https://github.com/docmost/docmost.git
synced 2026-08-28 01:07:08 +08:00
65 lines
2.2 KiB
TypeScript
65 lines
2.2 KiB
TypeScript
import { isNodeEmpty } from "@tiptap/core";
|
|
import { Plugin, PluginKey } from "@tiptap/pm/state";
|
|
import { Decoration, DecorationSet } from "@tiptap/pm/view";
|
|
import { Placeholder as TiptapPlaceholder } from "@tiptap/extensions";
|
|
|
|
export const Placeholder = TiptapPlaceholder.extend({
|
|
addProseMirrorPlugins() {
|
|
const editor = this.editor;
|
|
const options = this.options;
|
|
const dataAttribute = `data-${options.dataAttribute || "placeholder"}`;
|
|
|
|
return [
|
|
new Plugin({
|
|
key: new PluginKey("docmostPlaceholder"),
|
|
props: {
|
|
decorations: (state) => {
|
|
if (options.showOnlyWhenEditable && !editor.isEditable) {
|
|
return null;
|
|
}
|
|
|
|
const { doc, selection } = state;
|
|
const { anchor } = selection;
|
|
const decorations: Decoration[] = [];
|
|
const isEmptyDoc = editor.isEmpty;
|
|
|
|
doc.descendants((node, pos) => {
|
|
if (!node.type.isTextblock) {
|
|
return options.includeChildren;
|
|
}
|
|
|
|
const hasAnchor = anchor >= pos && anchor <= pos + node.nodeSize;
|
|
const isEmpty = !node.isLeaf && isNodeEmpty(node);
|
|
|
|
if ((hasAnchor || !options.showOnlyCurrent) && isEmpty) {
|
|
const emptyNodeClass =
|
|
typeof options.emptyNodeClass === "function"
|
|
? options.emptyNodeClass({ editor, node, pos, hasAnchor })
|
|
: options.emptyNodeClass;
|
|
const classes = [emptyNodeClass];
|
|
if (isEmptyDoc) {
|
|
classes.push(options.emptyEditorClass);
|
|
}
|
|
|
|
decorations.push(
|
|
Decoration.node(pos, pos + node.nodeSize, {
|
|
class: classes.join(" "),
|
|
[dataAttribute]:
|
|
typeof options.placeholder === "function"
|
|
? options.placeholder({ editor, node, pos, hasAnchor })
|
|
: options.placeholder,
|
|
}),
|
|
);
|
|
}
|
|
|
|
return options.includeChildren;
|
|
});
|
|
|
|
return DecorationSet.create(doc, decorations);
|
|
},
|
|
},
|
|
}),
|
|
];
|
|
},
|
|
});
|