JSFiddle - React, Tailwind, and code Playground
by Graham Dixon
HTML
<div class="hstlEditor" contenteditable="true">
<div class="container">
</div>
</div>
CSS
.hstlEditor {
outline: none;
-webkit-user-select: none !important;
-moz-user-select: none !important;
-ms-user-select: none !important;
user-select: none !important;
cursor: text;
color: transparent;
text-shadow: 0 0 0 black;
}
.line {
display: inline-block;
}
span>.blinking-cursor:first-child {
padding-left: 0px;
}
span.blinking-cursor {
font-weight: bold;
font-size: auto;
color: #2E3D48;
text-shadow: 0 0 0 transparent;
-webkit-animation: 1s blink step-end infinite;
-moz-animation: 1s blink step-end infinite;
-ms-animation: 1s blink step-end infinite;
-o-animation: 1s blink step-end infinite;
animation: 1s blink step-end infinite;
padding-left: 0px;
width: 5px;
display: inline-flex;
max-width: 6px;
overflow: hidden;
padding: 0px;
margin: 0px;
margin-left: -2.5px;
margin-right: -4.4px;
margin-top: -0px;
font-size: 100%;
position:relative;
top: 0px;
}
@keyframes "blink" {
from,
to {
color: black;
}
50% {
color: transparent;
}
}
@-moz-keyframes blink {
from,
to {
color: black;
}
50% {
color: transparent;
}
}
@-webkit-keyframes "blink" {
from,
to {
color: black;
}
50% {
color: transparent;
}
}
@-ms-keyframes "blink" {
from,
to {
color: black;
}
50% {
color: transparent;
}
}
@-o-keyframes "blink" {
from,
to {
color: black;
}
50% {
color: transparent;
}
}
JavaScript
// get a range from the current cursor position
const createRange = function(e, editor, scrollX, scrollY) {
// different environments use different methods to get to the same(ish) values
var range, textNode, offset, isIe;
// restore scroll position on the editor (focus/blur can knock the scroll pos back to 0)
editor.scrollLeft = scrollX;
editor.scrollTop = scrollY;
// switch to get the correct range from point method
if (document.caretPositionFromPoint) {
// standard uses caretPositionFromPoint
range = document.caretPositionFromPoint(e.pageX, e.pageY);
textNode = range && range.offsetNode;
offset = range && range.offset;
} else if (document.caretRangeFromPoint) {
// webkit uses caretRangeFromPoint
range = document.caretRangeFromPoint(e.pageX, e.pageY);
textNode = range && range.startContainer;
offset = range && range.startOffset;
} else if (document.body.createTextRange) {
// mark as IE type (returns textNode's parent as textNode)
isIe = true;
// random id to mark position
var posId = ("-%%%-"+ ("" + Math.random()).slice(6) +"-%%%-");
// create a range and align with current cursor position
textNode = document.body.createTextRange();
console.dir(textNode);
// textNode.offsetTop = e.pageY;
// textNode.offsetLeft = e.pageX;
// picks up element (textElement at position)
textNode.moveToPoint(e.pageX, e.pageY);
// place id into the node so we can discover the offset
textNode.text = posId;
// get the node the text is contained in
textNode = textNode.parentElement();
// position of the id marker in the textContent
offset = textNode.textContent.indexOf(posId);
// remove id marker
textNode.textContent = textNode.textContent.replace(posId, "");
// set the range to the textNodes.textContent container span
...