JSFiddle - React, Tailwind, and code Playground
by Josh Pullen
HTML
<div class="editorWrapper">
<div class="editor"></div>
<div class="cursor"></div>
</div>
CSS
.editorWrapper {
position:relative;
}
.editor {
min-width: 100px;
min-height: 100px;
background: #ddd;
font-family: monospace;
white-space: nowrap;
overflow-x: auto;
cursor: text;
}
.cursor {
position: absolute;
top: 0;
left: 0;
width: 1px;
height: 15px; /* Line height (should really be set by JS) */
background: red;
}
JavaScript
var editorWrapper = document.getElementsByClassName('editorWrapper')[0];
var editor = document.getElementsByClassName('editor')[0];
var cursor = document.getElementsByClassName('cursor')[0];
var phantomInput = document.createElement('textarea');
document.body.append(phantomInput);
var hasFocus = false;
const charWidth = 7;
const lineHeight = 15;
editorWrapper.addEventListener('click', function(e) {
let x = e.clientX - this.offsetLeft;
let y = e.clientY - this.offsetTop;
let col = Math.round(x / charWidth); // x in terms of characters
let row = Math.floor(y / lineHeight); // y in terms of lines
let lines = phantomInput.value.split('\n');
if(row > lines.length - 1) {
row = lines.length - 1;
col = lines[lines.length - 1].length;
} else if(col > lines[row].length) {
col = lines[row].length;
}
cursor.style.left = col * charWidth + 'px';
cursor.style.top = row * lineHeight + 'px';
phantomInput.focus();
phantomInput.selectionStart = phantomInput.selectionEnd = coordsToLoc(col, row);
});
phantomInput.addEventListener('focus', function() {
hasFocus = true;
editor.style.background = 'yellow';
cursor.style.display = 'block';
});
phantomInput.addEventListener('blur', function() {
hasFocus = false;
editor.style.background = '#ddd';
cursor.style.display = 'none';
});
function locToCoords(loc) {
// Convert numeric location in text to row/col coordinates
let lines = phantomInput.value.split('\n');
let row = 0;
let cumulativeLoc = 0;
while(cumulativeLoc + lines[row].length + 1 < loc) {
cumulativeLoc += lines[row].length + 1;
row++;
}
let col = loc - cumulativeLoc;
return {
'col': col,
'row': row
};
}
function coordsToLoc(col, row) {
let lines = phantomInput.value.split('\n');
let loc = 0;
for(let i = 0; i < row; i++) {
loc += lines[i].length + 1;
}
loc += col;
return loc;
}
function inputChange() {
editor.innerText = phantomInput.value;
let cursorCoords =...