JSFiddle - React, Tailwind, and code Playground
by jeremyblalock
December 15, 2014
HTML
<div class='wrapper'>
<div class='line-numbers'></div>
<textarea class='textarea' rows="4">Some good text to start us off. It's much easier to imagine this if we start with something...
Another line of awesome content...</textarea>
<div class='line-bg'></div>
</div>
<div class='indicator'></div>
CSS
* {
box-sizing: border-box;
}
body {
padding: 30px;
background: #eee;
font-size: 16px;
}
.wrapper {
background: #fff;
margin: bottom;
position: relative;
font-family: Monaco, fixed-width;
}
.textarea {
width: 100%;
font: inherit;
font-size: 13px;
outline: none !important;
border: none;
background: transparent;
display: block;
resize: none;
line-height: 20px;
position: relative;
z-index: 2;
padding-left: 55px;
}
.line-bg {
background: #dfd;
width: 100%;
top: 0;
height: 20px;
left: 0;
position: absolute;
visibility: hidden;
min-height: 20px;
}
.textarea:focus + .line-bg {
visibility: visible;
}
.line-numbers {
position: absolute;
left: 0;
top: 0;
bottom: 0;
width: 50px;
background: rgba(0, 0, 0, 0.03);
z-index: 1;
color: #999;
}
.line-numbers span {
position: absolute;
line-height: 20px;
left: 0;
padding-left: 5px;
font-size: 13px;
}
JavaScript
(function($, undefined) {
$.fn.getCursorPosition = function() {
var el = $(this).get(0);
var pos = el.selectionStart,
end = el.selectionEnd;
return [pos, end];
}
})(jQuery);
var $shadow = $('<div></div>'),
$ta = $('.textarea'),
$lineBg = $('.line-bg'),
$lineNumbers = $('.line-numbers'),
lineHeight = 20;
$('body').append($shadow);
function setup() {
$shadow.css({
font: $ta.css('font'),
width: $ta.width(),
lineHeight: lineHeight + 'px',
whiteSpace: 'pre-wrap',
position: 'fixed',
bottom: '100%'
});
}
function computeRowCount(text) {
$shadow.text(text);
var height = $shadow.height();
return height / lineHeight;
}
function getSelectionPosition(start, end) {
var text = $ta.val(),
$parent = $('<span></span>'),
$startSpan = $('<span></span>'),
$selectionSpan = $('<span></span>'),
$endSpan = $('<span></span>');
if (text.substring(text.length - 1).match(/[\r\n]/)) {
text += '.';
}
$startSpan.text(text.substring(0, start));
$selectionSpan.text(text.substring(start, end + 1));
$endSpan.text(text.substring(end + 1));
if (text.substring(start, end) == '') {
$selectionSpan.css({
//display: 'inline-block'
});
}
$parent.append($startSpan);
$parent.append($selectionSpan);
$parent.append($endSpan);
$shadow.html('');
$shadow.append($parent);
var y = $selectionSpan.position().top,
h = $selectionSpan.outerHeight();
return {top: y, height: h};
}
function setLineNumbers() {
var text = $ta.val(),
lines = text.split(/\n/),
soFarText = '',
$ln;
$lineNumbers.html('');
for (var i = 0; i < lines.length; i += 1) {
$ln = $('<span></span>');
$ln.text(i + 1);
$ln.css({
top: computeRowCount(soFarText) * 20
});
...