Firstly, you don’t want to put the DOM node in the widget’s value
field. The placeholder text would be a more reasonable thing to put there. Don’t worry about caching the DOM content, the editor won’t recreate DOM nodes for widget values that compare as equal, so just put the DOM creation in toDOM
.
Your plugin could look something like this:
class PlaceholderWidget extends WidgetType<string> {
toDOM() {
const placeHolder = document.createElement('div')
placeHolder.classList.add('placeholder')
placeHolder.textContent = this.value
return placeHolder
}
}
function placeholder(text: string) {
return ViewPlugin.fromClass(class {
decorations = Decoration.none
constructor(view: EditorView) { this.updateDeco(view.state) }
update(update: ViewUpdate) { this.updateDeco(update.state) }
updateDeco(state: EditorState) {
this.decorations = state.doc.length ? Decoration.none
: Decoration.set(Decoration.widget({widget: new PlaceholderWidget(text), side: 1}).range(0))
}
}).decorations()
}
But trying that out, I noticed that it still runs into the contentEditable issue with editing around widgets. The cursor becomes invisible and on Chrome I can’t even continue typing. So it looks like some more work will be needed before this is usable.