CanvasRenderingContext2D
canvas要素を適当に生やしてこれすると取れるよ!
sample.jsconst canvas = document.createElement('canvas');
const context = canvas.getContext('2d');
文字を計測するのはこんな感じ
お好みでフォントを指定して
計測
sample.jsconsole.log(context.measureText('ほげ').width);
繰り返し計測すれば、カーソルの位置を取得できるかな?

e.g.
sample2.jsconst text = 'ほげほげふがふが';
const cursor = {top:0, left: 72};
const canvas = document.createElement('canvas');
const context = canvas.getContext('2d');
context.font = '16px monospace';
const position = text.split('')
.find((_, i) => context.measureText(text.slice(0, i + 1)).width >= cursor.left)?.length
console.log(position);
実際に既存のテキストエディタの中で使われているのを見て知りました

自分だったらslice作ったりはしないだろうなーと思いながら見てる

見付かったら探索を打ち切りたい
打ち切ってみた
まあ即興で書いたコードなので

最初は
2分探索を使おうかと思いましたが、コード書くのがめんどくさかったので、愚直に最初から探索するアルゴリズムにしました