Hey there,
I have a widget that I need to locate in an absolute position using coordsAtPos
but an error is been thrown saying Error: Reading the editor layout isn't allowed during an update
.
Is there a proper way to position a widget with an absolute coordinates?
Thank you
This is my code:
import { Extension } from "@codemirror/state";
import { ViewPlugin, ViewUpdate } from "@codemirror/view";
import { Decoration, DecorationSet, WidgetType } from "@codemirror/view";
import { EditorView } from "@codemirror/view";
import { completionStatus, startCompletion } from "@codemirror/autocomplete";
import { getRange, replaceRange, setCursor } from "@/componentsLibrary/CodeEditor/v6/editorUtils";
export const openContext = (view: EditorView) => {
replaceRange(view, "{{ $. }}", view.state.selection.main.head);
setCursor(view, view.state.selection.main.head + 5);
startCompletion(view);
};
class ContextButton extends WidgetType {
private readonly _view: EditorView
constructor(readonly view: EditorView) {
super();
this._view = view;
}
toDOM(view: EditorView) {
const wrap = document.createElement("div");
wrap.onclick = (ev) => {
openContext(view);
ev.preventDefault();
};
const coords = view.coordsAtPos(view.state.selection.main.head); // the error thrown here
console.log({ coords });
wrap.className = "context-btn-action";
const iconEl = document.getElementById("context-button");
const clonedIcon = iconEl?.cloneNode(true) as HTMLElement;
clonedIcon.className = "";
clonedIcon.id = "";
wrap.appendChild(clonedIcon);
return wrap;
}
ignoreEvent() { return false; }
}
export function contextButton(): Extension {
return ViewPlugin.fromClass(class {
contextButton: DecorationSet
constructor(readonly view: EditorView) {
const cursorPos = view.state.selection.main.head;
this.contextButton = Decoration.set([Decoration.widget({ widget: new ContextButton(view), side: 1 }).range(cursorPos)]);
}
update(update: ViewUpdate) {
const range = getRange(update.view, update.view.state.selection.main.head - 1, update.view.state.selection.main.head + 1).trim();
if (completionStatus(update.state) !== null || !!range) {
this.contextButton = Decoration.none;
return;
}
if (!range) {
const cursorPos = update.view.state.selection.main.head;
this.contextButton = Decoration.set([Decoration.widget({ widget: new ContextButton(update.view), side: 1 }).range(cursorPos)]);
}
}
get decorations() { return !this.view.hasFocus ? Decoration.none : this.contextButton; }
}, { decorations: v => v.decorations });
}