-
-
Notifications
You must be signed in to change notification settings - Fork 2.4k
/
Copy pathplaceholder.ts
74 lines (62 loc) · 2.17 KB
/
placeholder.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
import { Editor, Extension } from '@tiptap/core'
import { Node as ProsemirrorNode } from 'prosemirror-model'
import { Decoration, DecorationSet } from 'prosemirror-view'
import { Plugin } from 'prosemirror-state'
export interface PlaceholderOptions {
emptyEditorClass: string,
emptyNodeClass: string,
placeholder: ((PlaceholderProps: {
editor: Editor,
node: ProsemirrorNode,
}) => string) | string,
showOnlyWhenEditable: boolean,
showOnlyCurrent: boolean,
}
export const Placeholder = Extension.create<PlaceholderOptions>({
name: 'placeholder',
defaultOptions: {
emptyEditorClass: 'is-editor-empty',
emptyNodeClass: 'is-empty',
placeholder: 'Write something …',
showOnlyWhenEditable: true,
showOnlyCurrent: true,
},
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.textContent
if ((hasAnchor || !this.options.showOnlyCurrent) && isEmpty) {
const classes = [this.options.emptyNodeClass]
if (this.editor.isEmpty) {
classes.push(this.options.emptyEditorClass)
}
const decoration = Decoration.node(pos, pos + node.nodeSize, {
class: classes.join(' '),
'data-placeholder': typeof this.options.placeholder === 'function'
? this.options.placeholder({
editor: this.editor,
node,
})
: this.options.placeholder,
})
decorations.push(decoration)
}
return false
})
return DecorationSet.create(doc, decorations)
},
},
}),
]
},
})