// Source: https://github.com/julianpoemp/codejar-linenumbers/blob/main/src/codejar-linenumbers.ts // This class was copied from https://github.com/antonmedv/codejar/blob/3.7.0/linenumbers.ts // and applied with further improvements and fixes type Options = { class: string wrapClass: string width: string backgroundColor: string color: string } export function withLineNumbers( highlight: (e: HTMLElement) => void, options: Partial = {} ) { const opts: Options = { class: "codejar-linenumbers", wrapClass: "codejar-wrap", width: "35px", backgroundColor: "rgba(128, 128, 128, 0.15)", color: "", ...options } let lineNumbers: HTMLElement return function (editor: HTMLElement) { highlight(editor) if (!lineNumbers) { lineNumbers = init(editor, opts) editor.addEventListener("scroll", () => lineNumbers.style.top = `-${editor.scrollTop}px`); } const code = editor.textContent || "" const linesCount = code.replace(/\n$/g, "").split("\n").length let text = "" for (let i = 0; i < linesCount; i++) { text += `${i + 1}\n` } lineNumbers.innerText = text } } function init(editor: HTMLElement, opts: Options): HTMLElement { const css = getComputedStyle(editor); const wrap = document.createElement("div") wrap.className = opts.wrapClass wrap.style.position = "relative" const innerWrap = document.createElement("div"); innerWrap.className = "codejar-linenumbers-inner-wrap"; innerWrap.style.background = css.background; innerWrap.style.marginTop = css.borderTopWidth; innerWrap.style.marginBottom = css.borderBottomWidth; innerWrap.style.marginLeft = css.borderLeftWidth; innerWrap.style.borderTopLeftRadius = css.borderTopLeftRadius; innerWrap.style.borderBottomLeftRadius = css.borderBottomLeftRadius; const gutter = document.createElement("div") gutter.className = opts.class; innerWrap.appendChild(gutter); wrap.appendChild(innerWrap) // Add own styles gutter.style.width = opts.width gutter.style.overflow = "hidden" gutter.style.backgroundColor = opts.backgroundColor // Copy editor styles gutter.style.fontFamily = css.fontFamily gutter.style.fontSize = css.fontSize gutter.style.lineHeight = css.lineHeight gutter.style.paddingTop = `calc(${css.paddingTop})`; gutter.style.paddingLeft = css.paddingLeft gutter.style.borderTopLeftRadius = css.borderTopLeftRadius gutter.style.borderBottomLeftRadius = css.borderBottomLeftRadius; // Add line numbers const lineNumbers = document.createElement("div"); lineNumbers.setAttribute("class", "codejar-linenumber"); lineNumbers.style.color = opts.color || css.color; lineNumbers.style.setProperty("mix-blend-mode", "unset"); gutter.appendChild(lineNumbers) // Tweak editor styles editor.style.paddingLeft = `calc(${opts.width} + ${gutter.style.paddingLeft} + 5px)` editor.style.whiteSpace = "pre" // Swap editor with a wrap editor.parentNode!.insertBefore(wrap, editor) wrap.appendChild(editor) return lineNumbers }