mirror of https://github.com/fantasticit/think.git
tiptap: dynamic placeholder
parent
ef2ed7eea9
commit
5146b0f5a2
|
@ -1,3 +1,95 @@
|
|||
import BuiltInPlaceholder from '@tiptap/extension-placeholder';
|
||||
import { Editor, Extension } from '@tiptap/core';
|
||||
import { Node as ProsemirrorNode } from 'prosemirror-model';
|
||||
import { Plugin } from 'prosemirror-state';
|
||||
import { Decoration, DecorationSet } from 'prosemirror-view';
|
||||
|
||||
export const Placeholder = BuiltInPlaceholder;
|
||||
export interface PlaceholderOptions {
|
||||
emptyEditorClass: string;
|
||||
emptyNodeClass: string;
|
||||
placeholder: ((PlaceholderProps: { editor: Editor; node: ProsemirrorNode; pos: number }) => string) | string;
|
||||
showOnlyWhenEditable: boolean;
|
||||
showOnlyCurrent: boolean;
|
||||
includeChildren: boolean;
|
||||
}
|
||||
|
||||
export const Placeholder = Extension.create<PlaceholderOptions>({
|
||||
name: 'placeholder',
|
||||
|
||||
addOptions() {
|
||||
return {
|
||||
emptyEditorClass: 'is-editor-empty',
|
||||
emptyNodeClass: 'is-empty',
|
||||
placeholder: 'Write something …',
|
||||
showOnlyWhenEditable: true,
|
||||
showOnlyCurrent: true,
|
||||
includeChildren: false,
|
||||
};
|
||||
},
|
||||
|
||||
addStorage() {
|
||||
return new Map();
|
||||
},
|
||||
|
||||
addProseMirrorPlugins() {
|
||||
return [
|
||||
new Plugin({
|
||||
props: {
|
||||
decorations: ({ doc, selection }) => {
|
||||
const active = this.editor.isEditable || !this.options.showOnlyWhenEditable;
|
||||
const { anchor } = selection;
|
||||
const decorations: Decoration[] = [];
|
||||
|
||||
if (!active) {
|
||||
return;
|
||||
}
|
||||
|
||||
doc.descendants((node, pos) => {
|
||||
const hasAnchor = anchor >= pos && anchor <= pos + node.nodeSize;
|
||||
const isEmpty = !node.isLeaf && !node.childCount;
|
||||
|
||||
if ((hasAnchor || !this.options.showOnlyCurrent) && isEmpty) {
|
||||
const classes = [this.options.emptyNodeClass];
|
||||
|
||||
if (this.editor.isEmpty) {
|
||||
classes.push(this.options.emptyEditorClass);
|
||||
}
|
||||
|
||||
const start = pos;
|
||||
const end = pos + node.nodeSize;
|
||||
const key = `${start}-${end}`;
|
||||
|
||||
if (!this.editor.storage[this.name].has(key)) {
|
||||
this.editor.storage[this.name].set(
|
||||
key,
|
||||
typeof this.options.placeholder === 'function'
|
||||
? this.options.placeholder({
|
||||
editor: this.editor,
|
||||
node,
|
||||
pos,
|
||||
})
|
||||
: this.options.placeholder
|
||||
);
|
||||
}
|
||||
|
||||
const decoration = Decoration.node(start, end, {
|
||||
'class': classes.join(' '),
|
||||
'data-placeholder': this.editor.storage[this.name].get(key),
|
||||
});
|
||||
|
||||
setTimeout(() => {
|
||||
this.editor.storage[this.name].delete(key);
|
||||
}, 500);
|
||||
|
||||
decorations.push(decoration);
|
||||
}
|
||||
|
||||
return this.options.includeChildren;
|
||||
});
|
||||
|
||||
return DecorationSet.create(doc, decorations);
|
||||
},
|
||||
},
|
||||
}),
|
||||
];
|
||||
},
|
||||
});
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
import { Toast } from '@douyinfe/semi-ui';
|
||||
import scrollIntoView from 'scroll-into-view-if-needed';
|
||||
// 自定义节点扩展
|
||||
import { Attachment } from 'tiptap/core/extensions/attachment';
|
||||
import { BackgroundColor } from 'tiptap/core/extensions/background-color';
|
||||
|
@ -78,6 +77,14 @@ const DocumentWithTitle = Document.extend({
|
|||
|
||||
export { Document };
|
||||
|
||||
const placeholders = [
|
||||
'输入 / 唤起更多',
|
||||
'使用 markdown 语法进行输入',
|
||||
'输入 @ 来提及他人',
|
||||
'输入 : 来插入表情',
|
||||
'你知道吗?输入 $katex 然后按一下空格就可以快速插入数学公式,其他节点操作类似哦',
|
||||
];
|
||||
|
||||
export const CollaborationKit = [
|
||||
Paragraph,
|
||||
Placeholder.configure({
|
||||
|
@ -88,7 +95,7 @@ export const CollaborationKit = [
|
|||
|
||||
if (!editor.isEditable) return;
|
||||
|
||||
return '输入 / 唤起更多';
|
||||
return placeholders[~~(Math.random() * placeholders.length)];
|
||||
},
|
||||
showOnlyCurrent: false,
|
||||
showOnlyWhenEditable: false,
|
||||
|
|
Loading…
Reference in New Issue