Hi,
I have implemented a StateField that uses Decoration.replace() to replace parts of a markdown document with actual html elements using widgets. However, if the widget is clickable (e.g. <a>
links) and the editor has focus, the element needs to be clicked twice: the first time the editor just loses focus and only the second time the element is actually clicked.
Am I doing something wrong? Ideally, I’d like to click only once while preserving the editor’s focus.
Here’s a simplified version of the code I’m running
class Link extends WidgetType {
constructor(
readonly node: SyntaxNode,
readonly state: EditorState,
) {
super();
}
toDOM() {
let link = document.createElement("a");
let marks = this.node.getChildren("LinkMark");
if (marks.length >= 2) {
link.innerText = this.state.sliceDoc(marks[0].to, marks[1].from);
}
let url = this.node.getChild("URL");
if (url) link.href = this.state.sliceDoc(url.from, url.to);
return link;
}
}
let decorationsField = StateField.define<DecorationSet>({
create() {
return Decoration.none;
},
update(_, tr) {
const builder = new RangeSetBuilder<Decoration>();
let cursor = tr.state.selection.main.head;
syntaxTree(tr.state).iterate({
enter: (node) => {
if ((cursor < node.from || cursor > node.to) && node.name == "Link") {
builder.add(
node.from,
node.to,
Decoration.replace({
widget: new Link(node.node, tr.state),
}),
);
return false;
}
return true;
},
});
return builder.finish();
},
provide: (f) => EditorView.decorations.from(f),
});
new EditorView({
doc: "[Test](https://example.com)",
extensions: [markdown(), decorationsField],
parent: document.body,
});
I was also able to reproduce this on codemirror.net