* Approximates pixel position of a text offset inside a textarea. * Uses a hidden mirror div that matches the textarea's styling.
( textarea: HTMLTextAreaElement, offset: number )
| 27 | * Uses a hidden mirror div that matches the textarea's styling. |
| 28 | */ |
| 29 | function measureCursorPosition( |
| 30 | textarea: HTMLTextAreaElement, |
| 31 | offset: number |
| 32 | ): { top: number; left: number } { |
| 33 | const mirror = document.createElement("div"); |
| 34 | const computed = window.getComputedStyle(textarea); |
| 35 | |
| 36 | mirror.style.position = "absolute"; |
| 37 | mirror.style.visibility = "hidden"; |
| 38 | mirror.style.whiteSpace = "pre-wrap"; |
| 39 | mirror.style.wordWrap = "break-word"; |
| 40 | mirror.style.width = computed.width; |
| 41 | mirror.style.font = computed.font; |
| 42 | mirror.style.lineHeight = computed.lineHeight; |
| 43 | mirror.style.padding = computed.padding; |
| 44 | mirror.style.border = computed.border; |
| 45 | mirror.style.boxSizing = computed.boxSizing; |
| 46 | |
| 47 | const text = textarea.value.slice(0, offset); |
| 48 | mirror.textContent = text; |
| 49 | |
| 50 | const span = document.createElement("span"); |
| 51 | span.textContent = "\u200b"; // zero-width space |
| 52 | mirror.appendChild(span); |
| 53 | |
| 54 | document.body.appendChild(mirror); |
| 55 | const rect = textarea.getBoundingClientRect(); |
| 56 | const spanRect = span.getBoundingClientRect(); |
| 57 | document.body.removeChild(mirror); |
| 58 | |
| 59 | return { |
| 60 | top: spanRect.top - rect.top + textarea.scrollTop, |
| 61 | left: spanRect.left - rect.left, |
| 62 | }; |
| 63 | } |
| 64 | |
| 65 | // ─── CursorGhost ───────────────────────────────────────────────────────────── |
| 66 |
no test coverage detected